{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Note: you may need to restart the kernel to use updated packages.\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "ERROR: Could not find a version that satisfies the requirement struct (from versions: none)\n",
      "ERROR: No matching distribution found for struct\n"
     ]
    }
   ],
   "source": [
    "pip install struct"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "b'\\x00\\x00\\x00\\x02'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import struct\n",
    "struct.pack(\">i\",2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "b'\\x02'"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "struct.pack(\">b\",2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2051, 60000, 28, 28)\n",
      "=========\n",
      "47040000\n",
      "=========\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "IOPub data rate exceeded.\n",
      "The notebook server will temporarily stop sending output\n",
      "to the client in order to avoid crashing it.\n",
      "To change this limit, set the config variable\n",
      "`--NotebookApp.iopub_data_rate_limit`.\n",
      "\n",
      "Current values:\n",
      "NotebookApp.iopub_data_rate_limit=1000000.0 (bytes/sec)\n",
      "NotebookApp.rate_limit_window=3.0 (secs)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "import struct\n",
    "with open(r\"C:\\Users\\Administrator\\Downloads\\第七周机器学习_分类训练\\第七周课件\\MNIST_data\\train-images-idx3-ubyte\",\"rb\") as f :\n",
    "    buffer = f.read(4 * 4)  # 4个int\n",
    "    head = struct.unpack('>iiii',buffer)\n",
    "    print(head)\n",
    "    print(\"===\"*3)\n",
    "    print(head[1]*head[2]*head[3])\n",
    "    buffer = f.read(head[1]*head[2]*head[3])\n",
    "    print(\"===\"*3)\n",
    "    print(buffer)\n",
    "    data = struct.unpack(\">{}b\".format(head[1]*head[2]*head[3]),buffer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(60000, 28, 28)"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "imgs = np.reshape(data,(head[1],head[2],head[3],))\n",
    "imgs.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPsAAAD4CAYAAAAq5pAIAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAOdklEQVR4nO3dfYxV9Z3H8c93EaIjVWBdESwu3UaNhiiYEY1sDFpFyh9iDV1BU1kfdjAW0yYk+IQW//BpWQskbiTTSgob1qZJIRBj1iISTU1oGBGRWdb1IWw7zARqyAjlaliH7/4xx82Ic393uOfcB+f7fiWTe+/53DPnmxs+nDv33HuPubsADH9/1egBANQHZQeCoOxAEJQdCIKyA0GcVs+NtbS0+JgxY+q5SSCU3t5elUolGyzLVXYzmy1ptaQRkn7p7s+k7j9mzBi1tbXl2SSAhPb29rJZ1U/jzWyEpH+V9H1Jl0paYGaXVvv7ANRWnr/Zp0v60N0/dvfjkn4taW4xYwEoWp6yny/pTwNud2XLvsLM2sysw8w6SqVSjs0ByCNP2Qd7EeBr771193Z3b3X31paWlhybA5BHnrJ3SZo04Pa3JXXnGwdAreQp+05JF5rZd8xslKT5krYUMxaAolV96M3dvzCzxZJeVf+ht7Xu3lnYZAAKles4u7u/IumVgmYBUEO8XRYIgrIDQVB2IAjKDgRB2YEgKDsQBGUHgqDsQBCUHQiCsgNBUHYgCMoOBEHZgSAoOxAEZQeCoOxAEJQdCIKyA0FQdiAIyg4EQdmBICg7EARlB4Kg7EAQlB0IgrIDQVB2IAjKDgRB2YEgcp3FFc1vxIgRyfzss8+u6fYfeOCBstnpp5+eXPeiiy6q+ndL0ooVK8pmt99+e3Ldzz//PJk/++yzyXz58uXJvBFyld3M9ks6KqlP0hfu3lrEUACKV8Se/Tp3/6SA3wOghvibHQgib9ld0u/M7G0zaxvsDmbWZmYdZtZRKpVybg5AtfI+jZ/h7t1mdq6krWb2X+7+5sA7uHu7pHZJmjhxoufcHoAq5dqzu3t3dnlI0iZJ04sYCkDxqi67mZ1pZt/68rqkWZL2FjUYgGLleRo/XtImM/vy9/y7u/9HIVMNMxdccEEyHzVqVDKfMWNGMr/mmmvKZmPGjEmuO2/evGSe1+OPP142W7p0aXLdrq6uZL569epkPn/+/LLZ0aNHk+vu3r07mb/xxhvJvBlVXXZ3/1jS5QXOAqCGOPQGBEHZgSAoOxAEZQeCoOxAEHzEtQBXXHFFMn/ttdeSeaWPmb7//vvJ/N57703mzaqvry+ZP/bYY8n82LFjVW+7u7s7mV955ZXJfPv27VVvu1HYswNBUHYgCMoOBEHZgSAoOxAEZQeCoOxAEBxnL8D+/fuT+SefpL+Ps9Zf55zHjh07knlvb28yv/7668tmx48fT667fv36ZI5Tw54dCIKyA0FQdiAIyg4EQdmBICg7EARlB4LgOHsBDh8+nMwffPDBZD5nzpxk/u677ybzSl+pnPLOO+8k81mzZiXzSp8pnzJlStms0imXFy1alMxxatizA0FQdiAIyg4EQdmBICg7EARlB4Kg7EAQ5u5129jEiRO9ra2tbtv7pjjrrLOSeaXTC69Zs6ZsVuk75e+8885kvmHDhmSO5tLe3q7u7m4bLKu4ZzeztWZ2yMz2Dlg2zsy2mtkH2eXYIgcGULyhPI3/laTZJy17SNI2d79Q0rbsNoAmVrHs7v6mpJPfDzpX0rrs+jpJtxQ8F4CCVfsC3Xh375Gk7PLccnc0szYz6zCzjlKpVOXmAORV81fj3b3d3VvdvbWlpaXWmwNQRrVlP2hmEyQpuzxU3EgAaqHasm+RtDC7vlDS5mLGAVArFT/PbmYvSZop6Rwz65L0M0nPSPqNmd0j6Y+SfljLIYe7I0eO5Fr/008/rXrdu+++O5nfeOONyfzEiRNVbxv1VbHs7r6gTPS9gmcBUEO8XRYIgrIDQVB2IAjKDgRB2YEg+CrpYeCJJ54om23ZsiW57syZM5N5pUNvr776ajJH82DPDgRB2YEgKDsQBGUHgqDsQBCUHQiCsgNBcJx9GEidNrnSV3fv2rUrmbe3tyfz119/verf//zzzyfXrefXnEfAnh0IgrIDQVB2IAjKDgRB2YEgKDsQBGUHguA4+zD30UcfJfO77rorma9duzaZVzrl86pVq8pmjz76aHLddevWJfOenp5kjq9izw4EQdmBICg7EARlB4Kg7EAQlB0IgrIDQXCcPbiNGzcm82uvvTaZr1ixIpnfcMMNZbMnn3wyue6aNWuS+VNPPZXMDxw4kMyjqbhnN7O1ZnbIzPYOWLbczA6Y2e7sZ05txwSQ11Cexv9K0uxBlq9096nZzyvFjgWgaBXL7u5vSjpch1kA1FCeF+gWm9me7Gn+2HJ3MrM2M+sws45SqZRjcwDyqLbsL0j6rqSpknokPVfuju7e7u6t7t7a0tJS5eYA5FVV2d39oLv3ufsJSb+QNL3YsQAUraqym9mEATd/IGlvufsCaA4Vj7Ob2UuSZko6x8y6JP1M0kwzmyrJJe2XtKiGM6KB9uzZk8xvu+22ZH7zzTeXzSp9Vv6+++5L5pXWv+mmm5J5NBXL7u4LBln8Yg1mAVBDvF0WCIKyA0FQdiAIyg4EQdmBIPiIK3Lp7e1N5uvXry+b9fX1Jdc97bT0P8+ZM2cm8+uuu65stn379uS6wxF7diAIyg4EQdmBICg7EARlB4Kg7EAQlB0IguPsSLr88suT+a233prMW1tby2azZw/2PaZD19nZmczPOOOMXL9/uGHPDgRB2YEgKDsQBGUHgqDsQBCUHQiCsgNBcJx9mLv44ouT+eLFi5N5pePoy5YtO+WZhqrS5917enqS+YkTJ4oc5xuPPTsQBGUHgqDsQBCUHQiCsgNBUHYgCMoOBMFx9m+A8847L5nfcccdZbP7778/uW6lvJZ27tyZzJ9++ulkPmrUqCLHGfYq7tnNbJKZbTezfWbWaWY/yZaPM7OtZvZBdjm29uMCqNZQnsZ/IWmJu18i6WpJPzazSyU9JGmbu18oaVt2G0CTqlh2d+9x913Z9aOS9kk6X9JcSeuyu62TdEuthgSQ3ym9QGdmkyVNk/QHSePdvUfq/w9B0rll1mkzsw4z6yiVSvmmBVC1IZfdzEZL+q2kn7r7kaGu5+7t7t7q7q0tLS3VzAigAEMqu5mNVH/RN7j7xmzxQTObkOUTJB2qzYgAilDx0JuZmaQXJe1z958PiLZIWijpmexyc00mHAbGjx+fzKdMmZLMV69encwPHDhQNps8eXJy3bx27NiRzJ977rmy2ciRI5Prbt7MP6kiDeU4+wxJP5L0npntzpY9ov6S/8bM7pH0R0k/rM2IAIpQsezu/ntJVib+XrHjAKgV3i4LBEHZgSAoOxAEZQeCoOxAEHzEdYjGjRtXNnvhhReS606bNi2Zd3d3J/NLLrkkmefx1ltvJfOVK1cm89GjRyfzjRs3JnPUD3t2IAjKDgRB2YEgKDsQBGUHgqDsQBCUHQgizHH2q6++OpkvWbIkmV911VVls3nz5lU1U1E+++yzstmqVauS61b6uuZNmzZVNROaD3t2IAjKDgRB2YEgKDsQBGUHgqDsQBCUHQgizHH2uXPnJvOlS5fWbNudnZ3J/OWXX07mfX19yTz13ezLli1Lrnvs2LFkjuGDPTsQBGUHgqDsQBCUHQiCsgNBUHYgCMoOBDGU87NPkrRe0nmSTkhqd/fVZrZc0j9J+nN210fc/ZVaDZrXww8/3LBtX3bZZbnySnp7e3OtjxiG8qaaLyQtcfddZvYtSW+b2dYsW+nu/1K78QAUZSjnZ++R1JNdP2pm+ySdX+vBABTrlP5mN7PJkqZJ+kO2aLGZ7TGztWY2tsw6bWbWYWYdpVIp17AAqjfkspvZaEm/lfRTdz8i6QVJ35U0Vf17/kHfoO3u7e7e6u6tLS0tBYwMoBpDKruZjVR/0Te4+0ZJcveD7t7n7ick/ULS9NqNCSCvimU3M5P0oqR97v7zAcsnDLjbDyTtLX48AEUZyqvxMyT9SNJ7ZrY7W/aIpAVmNlWSS9ovaVFNJgRQiKG8Gv97STZI1LTH1AF8He+gA4Kg7EAQlB0IgrIDQVB2IAjKDgRB2YEgKDsQBGUHgqDsQBCUHQiCsgNBUHYgCMoOBGHuXr+Nmf1Z0v8MWHSOpE/qNsCpadbZmnUuidmqVeRsf+vufzNYUNeyf23jZh3u3tqwARKadbZmnUtitmrVazaexgNBUHYgiEaXvb3B209p1tmadS6J2apVl9ka+jc7gPpp9J4dQJ1QdiCIhpTdzGab2ftm9qGZPdSIGcoxs/1m9p6Z7TazjgbPstbMDpnZ3gHLxpnZVjP7ILsc9Bx7DZptuZkdyB673WY2p0GzTTKz7Wa2z8w6zewn2fKGPnaJueryuNX9b3YzGyHpvyXdKKlL0k5JC9z9P+s6SBlmtl9Sq7s3/A0YZnatpL9IWu/uU7Jl/yzpsLs/k/1HOdbdH2yS2ZZL+kujT+Odna1owsDTjEu6RdI/qoGPXWKuf1AdHrdG7NmnS/rQ3T929+OSfi1pbgPmaHru/qakwyctnitpXXZ9nfr/sdRdmdmagrv3uPuu7PpRSV+eZryhj11irrpoRNnPl/SnAbe71Fzne3dJvzOzt82srdHDDGK8u/dI/f94JJ3b4HlOVvE03vV00mnGm+axq+b053k1ouyDnUqqmY7/zXD3KyR9X9KPs6erGJohnca7XgY5zXhTqPb053k1ouxdkiYNuP1tSd0NmGNQ7t6dXR6StEnNdyrqg1+eQTe7PNTgef5fM53Ge7DTjKsJHrtGnv68EWXfKelCM/uOmY2SNF/SlgbM8TVmdmb2wonM7ExJs9R8p6LeImlhdn2hpM0NnOUrmuU03uVOM64GP3YNP/25u9f9R9Ic9b8i/5GkRxsxQ5m5/k7Su9lPZ6Nnk/SS+p/W/a/6nxHdI+mvJW2T9EF2Oa6JZvs3Se9J2qP+Yk1o0Gx/r/4/DfdI2p39zGn0Y5eYqy6PG2+XBYLgHXRAEJQdCIKyA0FQdiAIyg4EQdmBICg7EMT/AeMDWOM0iC49AAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "for i in range(5):\n",
    "    plt.imshow(imgs[i],cmap = \"gray\")\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'data': array([[0., 0., 0., ..., 0., 0., 0.],\n",
       "        [0., 0., 0., ..., 0., 0., 0.],\n",
       "        [0., 0., 0., ..., 0., 0., 0.],\n",
       "        ...,\n",
       "        [0., 0., 0., ..., 0., 0., 0.],\n",
       "        [0., 0., 0., ..., 0., 0., 0.],\n",
       "        [0., 0., 0., ..., 0., 0., 0.]]),\n",
       " 'target': array(['5', '0', '4', ..., '4', '5', '6'], dtype=object),\n",
       " 'frame': None,\n",
       " 'feature_names': ['pixel1',\n",
       "  'pixel2',\n",
       "  'pixel3',\n",
       "  'pixel4',\n",
       "  'pixel5',\n",
       "  'pixel6',\n",
       "  'pixel7',\n",
       "  'pixel8',\n",
       "  'pixel9',\n",
       "  'pixel10',\n",
       "  'pixel11',\n",
       "  'pixel12',\n",
       "  'pixel13',\n",
       "  'pixel14',\n",
       "  'pixel15',\n",
       "  'pixel16',\n",
       "  'pixel17',\n",
       "  'pixel18',\n",
       "  'pixel19',\n",
       "  'pixel20',\n",
       "  'pixel21',\n",
       "  'pixel22',\n",
       "  'pixel23',\n",
       "  'pixel24',\n",
       "  'pixel25',\n",
       "  'pixel26',\n",
       "  'pixel27',\n",
       "  'pixel28',\n",
       "  'pixel29',\n",
       "  'pixel30',\n",
       "  'pixel31',\n",
       "  'pixel32',\n",
       "  'pixel33',\n",
       "  'pixel34',\n",
       "  'pixel35',\n",
       "  'pixel36',\n",
       "  'pixel37',\n",
       "  'pixel38',\n",
       "  'pixel39',\n",
       "  'pixel40',\n",
       "  'pixel41',\n",
       "  'pixel42',\n",
       "  'pixel43',\n",
       "  'pixel44',\n",
       "  'pixel45',\n",
       "  'pixel46',\n",
       "  'pixel47',\n",
       "  'pixel48',\n",
       "  'pixel49',\n",
       "  'pixel50',\n",
       "  'pixel51',\n",
       "  'pixel52',\n",
       "  'pixel53',\n",
       "  'pixel54',\n",
       "  'pixel55',\n",
       "  'pixel56',\n",
       "  'pixel57',\n",
       "  'pixel58',\n",
       "  'pixel59',\n",
       "  'pixel60',\n",
       "  'pixel61',\n",
       "  'pixel62',\n",
       "  'pixel63',\n",
       "  'pixel64',\n",
       "  'pixel65',\n",
       "  'pixel66',\n",
       "  'pixel67',\n",
       "  'pixel68',\n",
       "  'pixel69',\n",
       "  'pixel70',\n",
       "  'pixel71',\n",
       "  'pixel72',\n",
       "  'pixel73',\n",
       "  'pixel74',\n",
       "  'pixel75',\n",
       "  'pixel76',\n",
       "  'pixel77',\n",
       "  'pixel78',\n",
       "  'pixel79',\n",
       "  'pixel80',\n",
       "  'pixel81',\n",
       "  'pixel82',\n",
       "  'pixel83',\n",
       "  'pixel84',\n",
       "  'pixel85',\n",
       "  'pixel86',\n",
       "  'pixel87',\n",
       "  'pixel88',\n",
       "  'pixel89',\n",
       "  'pixel90',\n",
       "  'pixel91',\n",
       "  'pixel92',\n",
       "  'pixel93',\n",
       "  'pixel94',\n",
       "  'pixel95',\n",
       "  'pixel96',\n",
       "  'pixel97',\n",
       "  'pixel98',\n",
       "  'pixel99',\n",
       "  'pixel100',\n",
       "  'pixel101',\n",
       "  'pixel102',\n",
       "  'pixel103',\n",
       "  'pixel104',\n",
       "  'pixel105',\n",
       "  'pixel106',\n",
       "  'pixel107',\n",
       "  'pixel108',\n",
       "  'pixel109',\n",
       "  'pixel110',\n",
       "  'pixel111',\n",
       "  'pixel112',\n",
       "  'pixel113',\n",
       "  'pixel114',\n",
       "  'pixel115',\n",
       "  'pixel116',\n",
       "  'pixel117',\n",
       "  'pixel118',\n",
       "  'pixel119',\n",
       "  'pixel120',\n",
       "  'pixel121',\n",
       "  'pixel122',\n",
       "  'pixel123',\n",
       "  'pixel124',\n",
       "  'pixel125',\n",
       "  'pixel126',\n",
       "  'pixel127',\n",
       "  'pixel128',\n",
       "  'pixel129',\n",
       "  'pixel130',\n",
       "  'pixel131',\n",
       "  'pixel132',\n",
       "  'pixel133',\n",
       "  'pixel134',\n",
       "  'pixel135',\n",
       "  'pixel136',\n",
       "  'pixel137',\n",
       "  'pixel138',\n",
       "  'pixel139',\n",
       "  'pixel140',\n",
       "  'pixel141',\n",
       "  'pixel142',\n",
       "  'pixel143',\n",
       "  'pixel144',\n",
       "  'pixel145',\n",
       "  'pixel146',\n",
       "  'pixel147',\n",
       "  'pixel148',\n",
       "  'pixel149',\n",
       "  'pixel150',\n",
       "  'pixel151',\n",
       "  'pixel152',\n",
       "  'pixel153',\n",
       "  'pixel154',\n",
       "  'pixel155',\n",
       "  'pixel156',\n",
       "  'pixel157',\n",
       "  'pixel158',\n",
       "  'pixel159',\n",
       "  'pixel160',\n",
       "  'pixel161',\n",
       "  'pixel162',\n",
       "  'pixel163',\n",
       "  'pixel164',\n",
       "  'pixel165',\n",
       "  'pixel166',\n",
       "  'pixel167',\n",
       "  'pixel168',\n",
       "  'pixel169',\n",
       "  'pixel170',\n",
       "  'pixel171',\n",
       "  'pixel172',\n",
       "  'pixel173',\n",
       "  'pixel174',\n",
       "  'pixel175',\n",
       "  'pixel176',\n",
       "  'pixel177',\n",
       "  'pixel178',\n",
       "  'pixel179',\n",
       "  'pixel180',\n",
       "  'pixel181',\n",
       "  'pixel182',\n",
       "  'pixel183',\n",
       "  'pixel184',\n",
       "  'pixel185',\n",
       "  'pixel186',\n",
       "  'pixel187',\n",
       "  'pixel188',\n",
       "  'pixel189',\n",
       "  'pixel190',\n",
       "  'pixel191',\n",
       "  'pixel192',\n",
       "  'pixel193',\n",
       "  'pixel194',\n",
       "  'pixel195',\n",
       "  'pixel196',\n",
       "  'pixel197',\n",
       "  'pixel198',\n",
       "  'pixel199',\n",
       "  'pixel200',\n",
       "  'pixel201',\n",
       "  'pixel202',\n",
       "  'pixel203',\n",
       "  'pixel204',\n",
       "  'pixel205',\n",
       "  'pixel206',\n",
       "  'pixel207',\n",
       "  'pixel208',\n",
       "  'pixel209',\n",
       "  'pixel210',\n",
       "  'pixel211',\n",
       "  'pixel212',\n",
       "  'pixel213',\n",
       "  'pixel214',\n",
       "  'pixel215',\n",
       "  'pixel216',\n",
       "  'pixel217',\n",
       "  'pixel218',\n",
       "  'pixel219',\n",
       "  'pixel220',\n",
       "  'pixel221',\n",
       "  'pixel222',\n",
       "  'pixel223',\n",
       "  'pixel224',\n",
       "  'pixel225',\n",
       "  'pixel226',\n",
       "  'pixel227',\n",
       "  'pixel228',\n",
       "  'pixel229',\n",
       "  'pixel230',\n",
       "  'pixel231',\n",
       "  'pixel232',\n",
       "  'pixel233',\n",
       "  'pixel234',\n",
       "  'pixel235',\n",
       "  'pixel236',\n",
       "  'pixel237',\n",
       "  'pixel238',\n",
       "  'pixel239',\n",
       "  'pixel240',\n",
       "  'pixel241',\n",
       "  'pixel242',\n",
       "  'pixel243',\n",
       "  'pixel244',\n",
       "  'pixel245',\n",
       "  'pixel246',\n",
       "  'pixel247',\n",
       "  'pixel248',\n",
       "  'pixel249',\n",
       "  'pixel250',\n",
       "  'pixel251',\n",
       "  'pixel252',\n",
       "  'pixel253',\n",
       "  'pixel254',\n",
       "  'pixel255',\n",
       "  'pixel256',\n",
       "  'pixel257',\n",
       "  'pixel258',\n",
       "  'pixel259',\n",
       "  'pixel260',\n",
       "  'pixel261',\n",
       "  'pixel262',\n",
       "  'pixel263',\n",
       "  'pixel264',\n",
       "  'pixel265',\n",
       "  'pixel266',\n",
       "  'pixel267',\n",
       "  'pixel268',\n",
       "  'pixel269',\n",
       "  'pixel270',\n",
       "  'pixel271',\n",
       "  'pixel272',\n",
       "  'pixel273',\n",
       "  'pixel274',\n",
       "  'pixel275',\n",
       "  'pixel276',\n",
       "  'pixel277',\n",
       "  'pixel278',\n",
       "  'pixel279',\n",
       "  'pixel280',\n",
       "  'pixel281',\n",
       "  'pixel282',\n",
       "  'pixel283',\n",
       "  'pixel284',\n",
       "  'pixel285',\n",
       "  'pixel286',\n",
       "  'pixel287',\n",
       "  'pixel288',\n",
       "  'pixel289',\n",
       "  'pixel290',\n",
       "  'pixel291',\n",
       "  'pixel292',\n",
       "  'pixel293',\n",
       "  'pixel294',\n",
       "  'pixel295',\n",
       "  'pixel296',\n",
       "  'pixel297',\n",
       "  'pixel298',\n",
       "  'pixel299',\n",
       "  'pixel300',\n",
       "  'pixel301',\n",
       "  'pixel302',\n",
       "  'pixel303',\n",
       "  'pixel304',\n",
       "  'pixel305',\n",
       "  'pixel306',\n",
       "  'pixel307',\n",
       "  'pixel308',\n",
       "  'pixel309',\n",
       "  'pixel310',\n",
       "  'pixel311',\n",
       "  'pixel312',\n",
       "  'pixel313',\n",
       "  'pixel314',\n",
       "  'pixel315',\n",
       "  'pixel316',\n",
       "  'pixel317',\n",
       "  'pixel318',\n",
       "  'pixel319',\n",
       "  'pixel320',\n",
       "  'pixel321',\n",
       "  'pixel322',\n",
       "  'pixel323',\n",
       "  'pixel324',\n",
       "  'pixel325',\n",
       "  'pixel326',\n",
       "  'pixel327',\n",
       "  'pixel328',\n",
       "  'pixel329',\n",
       "  'pixel330',\n",
       "  'pixel331',\n",
       "  'pixel332',\n",
       "  'pixel333',\n",
       "  'pixel334',\n",
       "  'pixel335',\n",
       "  'pixel336',\n",
       "  'pixel337',\n",
       "  'pixel338',\n",
       "  'pixel339',\n",
       "  'pixel340',\n",
       "  'pixel341',\n",
       "  'pixel342',\n",
       "  'pixel343',\n",
       "  'pixel344',\n",
       "  'pixel345',\n",
       "  'pixel346',\n",
       "  'pixel347',\n",
       "  'pixel348',\n",
       "  'pixel349',\n",
       "  'pixel350',\n",
       "  'pixel351',\n",
       "  'pixel352',\n",
       "  'pixel353',\n",
       "  'pixel354',\n",
       "  'pixel355',\n",
       "  'pixel356',\n",
       "  'pixel357',\n",
       "  'pixel358',\n",
       "  'pixel359',\n",
       "  'pixel360',\n",
       "  'pixel361',\n",
       "  'pixel362',\n",
       "  'pixel363',\n",
       "  'pixel364',\n",
       "  'pixel365',\n",
       "  'pixel366',\n",
       "  'pixel367',\n",
       "  'pixel368',\n",
       "  'pixel369',\n",
       "  'pixel370',\n",
       "  'pixel371',\n",
       "  'pixel372',\n",
       "  'pixel373',\n",
       "  'pixel374',\n",
       "  'pixel375',\n",
       "  'pixel376',\n",
       "  'pixel377',\n",
       "  'pixel378',\n",
       "  'pixel379',\n",
       "  'pixel380',\n",
       "  'pixel381',\n",
       "  'pixel382',\n",
       "  'pixel383',\n",
       "  'pixel384',\n",
       "  'pixel385',\n",
       "  'pixel386',\n",
       "  'pixel387',\n",
       "  'pixel388',\n",
       "  'pixel389',\n",
       "  'pixel390',\n",
       "  'pixel391',\n",
       "  'pixel392',\n",
       "  'pixel393',\n",
       "  'pixel394',\n",
       "  'pixel395',\n",
       "  'pixel396',\n",
       "  'pixel397',\n",
       "  'pixel398',\n",
       "  'pixel399',\n",
       "  'pixel400',\n",
       "  'pixel401',\n",
       "  'pixel402',\n",
       "  'pixel403',\n",
       "  'pixel404',\n",
       "  'pixel405',\n",
       "  'pixel406',\n",
       "  'pixel407',\n",
       "  'pixel408',\n",
       "  'pixel409',\n",
       "  'pixel410',\n",
       "  'pixel411',\n",
       "  'pixel412',\n",
       "  'pixel413',\n",
       "  'pixel414',\n",
       "  'pixel415',\n",
       "  'pixel416',\n",
       "  'pixel417',\n",
       "  'pixel418',\n",
       "  'pixel419',\n",
       "  'pixel420',\n",
       "  'pixel421',\n",
       "  'pixel422',\n",
       "  'pixel423',\n",
       "  'pixel424',\n",
       "  'pixel425',\n",
       "  'pixel426',\n",
       "  'pixel427',\n",
       "  'pixel428',\n",
       "  'pixel429',\n",
       "  'pixel430',\n",
       "  'pixel431',\n",
       "  'pixel432',\n",
       "  'pixel433',\n",
       "  'pixel434',\n",
       "  'pixel435',\n",
       "  'pixel436',\n",
       "  'pixel437',\n",
       "  'pixel438',\n",
       "  'pixel439',\n",
       "  'pixel440',\n",
       "  'pixel441',\n",
       "  'pixel442',\n",
       "  'pixel443',\n",
       "  'pixel444',\n",
       "  'pixel445',\n",
       "  'pixel446',\n",
       "  'pixel447',\n",
       "  'pixel448',\n",
       "  'pixel449',\n",
       "  'pixel450',\n",
       "  'pixel451',\n",
       "  'pixel452',\n",
       "  'pixel453',\n",
       "  'pixel454',\n",
       "  'pixel455',\n",
       "  'pixel456',\n",
       "  'pixel457',\n",
       "  'pixel458',\n",
       "  'pixel459',\n",
       "  'pixel460',\n",
       "  'pixel461',\n",
       "  'pixel462',\n",
       "  'pixel463',\n",
       "  'pixel464',\n",
       "  'pixel465',\n",
       "  'pixel466',\n",
       "  'pixel467',\n",
       "  'pixel468',\n",
       "  'pixel469',\n",
       "  'pixel470',\n",
       "  'pixel471',\n",
       "  'pixel472',\n",
       "  'pixel473',\n",
       "  'pixel474',\n",
       "  'pixel475',\n",
       "  'pixel476',\n",
       "  'pixel477',\n",
       "  'pixel478',\n",
       "  'pixel479',\n",
       "  'pixel480',\n",
       "  'pixel481',\n",
       "  'pixel482',\n",
       "  'pixel483',\n",
       "  'pixel484',\n",
       "  'pixel485',\n",
       "  'pixel486',\n",
       "  'pixel487',\n",
       "  'pixel488',\n",
       "  'pixel489',\n",
       "  'pixel490',\n",
       "  'pixel491',\n",
       "  'pixel492',\n",
       "  'pixel493',\n",
       "  'pixel494',\n",
       "  'pixel495',\n",
       "  'pixel496',\n",
       "  'pixel497',\n",
       "  'pixel498',\n",
       "  'pixel499',\n",
       "  'pixel500',\n",
       "  'pixel501',\n",
       "  'pixel502',\n",
       "  'pixel503',\n",
       "  'pixel504',\n",
       "  'pixel505',\n",
       "  'pixel506',\n",
       "  'pixel507',\n",
       "  'pixel508',\n",
       "  'pixel509',\n",
       "  'pixel510',\n",
       "  'pixel511',\n",
       "  'pixel512',\n",
       "  'pixel513',\n",
       "  'pixel514',\n",
       "  'pixel515',\n",
       "  'pixel516',\n",
       "  'pixel517',\n",
       "  'pixel518',\n",
       "  'pixel519',\n",
       "  'pixel520',\n",
       "  'pixel521',\n",
       "  'pixel522',\n",
       "  'pixel523',\n",
       "  'pixel524',\n",
       "  'pixel525',\n",
       "  'pixel526',\n",
       "  'pixel527',\n",
       "  'pixel528',\n",
       "  'pixel529',\n",
       "  'pixel530',\n",
       "  'pixel531',\n",
       "  'pixel532',\n",
       "  'pixel533',\n",
       "  'pixel534',\n",
       "  'pixel535',\n",
       "  'pixel536',\n",
       "  'pixel537',\n",
       "  'pixel538',\n",
       "  'pixel539',\n",
       "  'pixel540',\n",
       "  'pixel541',\n",
       "  'pixel542',\n",
       "  'pixel543',\n",
       "  'pixel544',\n",
       "  'pixel545',\n",
       "  'pixel546',\n",
       "  'pixel547',\n",
       "  'pixel548',\n",
       "  'pixel549',\n",
       "  'pixel550',\n",
       "  'pixel551',\n",
       "  'pixel552',\n",
       "  'pixel553',\n",
       "  'pixel554',\n",
       "  'pixel555',\n",
       "  'pixel556',\n",
       "  'pixel557',\n",
       "  'pixel558',\n",
       "  'pixel559',\n",
       "  'pixel560',\n",
       "  'pixel561',\n",
       "  'pixel562',\n",
       "  'pixel563',\n",
       "  'pixel564',\n",
       "  'pixel565',\n",
       "  'pixel566',\n",
       "  'pixel567',\n",
       "  'pixel568',\n",
       "  'pixel569',\n",
       "  'pixel570',\n",
       "  'pixel571',\n",
       "  'pixel572',\n",
       "  'pixel573',\n",
       "  'pixel574',\n",
       "  'pixel575',\n",
       "  'pixel576',\n",
       "  'pixel577',\n",
       "  'pixel578',\n",
       "  'pixel579',\n",
       "  'pixel580',\n",
       "  'pixel581',\n",
       "  'pixel582',\n",
       "  'pixel583',\n",
       "  'pixel584',\n",
       "  'pixel585',\n",
       "  'pixel586',\n",
       "  'pixel587',\n",
       "  'pixel588',\n",
       "  'pixel589',\n",
       "  'pixel590',\n",
       "  'pixel591',\n",
       "  'pixel592',\n",
       "  'pixel593',\n",
       "  'pixel594',\n",
       "  'pixel595',\n",
       "  'pixel596',\n",
       "  'pixel597',\n",
       "  'pixel598',\n",
       "  'pixel599',\n",
       "  'pixel600',\n",
       "  'pixel601',\n",
       "  'pixel602',\n",
       "  'pixel603',\n",
       "  'pixel604',\n",
       "  'pixel605',\n",
       "  'pixel606',\n",
       "  'pixel607',\n",
       "  'pixel608',\n",
       "  'pixel609',\n",
       "  'pixel610',\n",
       "  'pixel611',\n",
       "  'pixel612',\n",
       "  'pixel613',\n",
       "  'pixel614',\n",
       "  'pixel615',\n",
       "  'pixel616',\n",
       "  'pixel617',\n",
       "  'pixel618',\n",
       "  'pixel619',\n",
       "  'pixel620',\n",
       "  'pixel621',\n",
       "  'pixel622',\n",
       "  'pixel623',\n",
       "  'pixel624',\n",
       "  'pixel625',\n",
       "  'pixel626',\n",
       "  'pixel627',\n",
       "  'pixel628',\n",
       "  'pixel629',\n",
       "  'pixel630',\n",
       "  'pixel631',\n",
       "  'pixel632',\n",
       "  'pixel633',\n",
       "  'pixel634',\n",
       "  'pixel635',\n",
       "  'pixel636',\n",
       "  'pixel637',\n",
       "  'pixel638',\n",
       "  'pixel639',\n",
       "  'pixel640',\n",
       "  'pixel641',\n",
       "  'pixel642',\n",
       "  'pixel643',\n",
       "  'pixel644',\n",
       "  'pixel645',\n",
       "  'pixel646',\n",
       "  'pixel647',\n",
       "  'pixel648',\n",
       "  'pixel649',\n",
       "  'pixel650',\n",
       "  'pixel651',\n",
       "  'pixel652',\n",
       "  'pixel653',\n",
       "  'pixel654',\n",
       "  'pixel655',\n",
       "  'pixel656',\n",
       "  'pixel657',\n",
       "  'pixel658',\n",
       "  'pixel659',\n",
       "  'pixel660',\n",
       "  'pixel661',\n",
       "  'pixel662',\n",
       "  'pixel663',\n",
       "  'pixel664',\n",
       "  'pixel665',\n",
       "  'pixel666',\n",
       "  'pixel667',\n",
       "  'pixel668',\n",
       "  'pixel669',\n",
       "  'pixel670',\n",
       "  'pixel671',\n",
       "  'pixel672',\n",
       "  'pixel673',\n",
       "  'pixel674',\n",
       "  'pixel675',\n",
       "  'pixel676',\n",
       "  'pixel677',\n",
       "  'pixel678',\n",
       "  'pixel679',\n",
       "  'pixel680',\n",
       "  'pixel681',\n",
       "  'pixel682',\n",
       "  'pixel683',\n",
       "  'pixel684',\n",
       "  'pixel685',\n",
       "  'pixel686',\n",
       "  'pixel687',\n",
       "  'pixel688',\n",
       "  'pixel689',\n",
       "  'pixel690',\n",
       "  'pixel691',\n",
       "  'pixel692',\n",
       "  'pixel693',\n",
       "  'pixel694',\n",
       "  'pixel695',\n",
       "  'pixel696',\n",
       "  'pixel697',\n",
       "  'pixel698',\n",
       "  'pixel699',\n",
       "  'pixel700',\n",
       "  'pixel701',\n",
       "  'pixel702',\n",
       "  'pixel703',\n",
       "  'pixel704',\n",
       "  'pixel705',\n",
       "  'pixel706',\n",
       "  'pixel707',\n",
       "  'pixel708',\n",
       "  'pixel709',\n",
       "  'pixel710',\n",
       "  'pixel711',\n",
       "  'pixel712',\n",
       "  'pixel713',\n",
       "  'pixel714',\n",
       "  'pixel715',\n",
       "  'pixel716',\n",
       "  'pixel717',\n",
       "  'pixel718',\n",
       "  'pixel719',\n",
       "  'pixel720',\n",
       "  'pixel721',\n",
       "  'pixel722',\n",
       "  'pixel723',\n",
       "  'pixel724',\n",
       "  'pixel725',\n",
       "  'pixel726',\n",
       "  'pixel727',\n",
       "  'pixel728',\n",
       "  'pixel729',\n",
       "  'pixel730',\n",
       "  'pixel731',\n",
       "  'pixel732',\n",
       "  'pixel733',\n",
       "  'pixel734',\n",
       "  'pixel735',\n",
       "  'pixel736',\n",
       "  'pixel737',\n",
       "  'pixel738',\n",
       "  'pixel739',\n",
       "  'pixel740',\n",
       "  'pixel741',\n",
       "  'pixel742',\n",
       "  'pixel743',\n",
       "  'pixel744',\n",
       "  'pixel745',\n",
       "  'pixel746',\n",
       "  'pixel747',\n",
       "  'pixel748',\n",
       "  'pixel749',\n",
       "  'pixel750',\n",
       "  'pixel751',\n",
       "  'pixel752',\n",
       "  'pixel753',\n",
       "  'pixel754',\n",
       "  'pixel755',\n",
       "  'pixel756',\n",
       "  'pixel757',\n",
       "  'pixel758',\n",
       "  'pixel759',\n",
       "  'pixel760',\n",
       "  'pixel761',\n",
       "  'pixel762',\n",
       "  'pixel763',\n",
       "  'pixel764',\n",
       "  'pixel765',\n",
       "  'pixel766',\n",
       "  'pixel767',\n",
       "  'pixel768',\n",
       "  'pixel769',\n",
       "  'pixel770',\n",
       "  'pixel771',\n",
       "  'pixel772',\n",
       "  'pixel773',\n",
       "  'pixel774',\n",
       "  'pixel775',\n",
       "  'pixel776',\n",
       "  'pixel777',\n",
       "  'pixel778',\n",
       "  'pixel779',\n",
       "  'pixel780',\n",
       "  'pixel781',\n",
       "  'pixel782',\n",
       "  'pixel783',\n",
       "  'pixel784'],\n",
       " 'target_names': ['class'],\n",
       " 'DESCR': \"**Author**: Yann LeCun, Corinna Cortes, Christopher J.C. Burges  \\n**Source**: [MNIST Website](http://yann.lecun.com/exdb/mnist/) - Date unknown  \\n**Please cite**:  \\n\\nThe MNIST database of handwritten digits with 784 features, raw data available at: http://yann.lecun.com/exdb/mnist/. It can be split in a training set of the first 60,000 examples, and a test set of 10,000 examples  \\n\\nIt is a subset of a larger set available from NIST. The digits have been size-normalized and centered in a fixed-size image. It is a good database for people who want to try learning techniques and pattern recognition methods on real-world data while spending minimal efforts on preprocessing and formatting. The original black and white (bilevel) images from NIST were size normalized to fit in a 20x20 pixel box while preserving their aspect ratio. The resulting images contain grey levels as a result of the anti-aliasing technique used by the normalization algorithm. the images were centered in a 28x28 image by computing the center of mass of the pixels, and translating the image so as to position this point at the center of the 28x28 field.  \\n\\nWith some classification methods (particularly template-based methods, such as SVM and K-nearest neighbors), the error rate improves when the digits are centered by bounding box rather than center of mass. If you do this kind of pre-processing, you should report it in your publications. The MNIST database was constructed from NIST's NIST originally designated SD-3 as their training set and SD-1 as their test set. However, SD-3 is much cleaner and easier to recognize than SD-1. The reason for this can be found on the fact that SD-3 was collected among Census Bureau employees, while SD-1 was collected among high-school students. Drawing sensible conclusions from learning experiments requires that the result be independent of the choice of training set and test among the complete set of samples. Therefore it was necessary to build a new database by mixing NIST's datasets.  \\n\\nThe MNIST training set is composed of 30,000 patterns from SD-3 and 30,000 patterns from SD-1. Our test set was composed of 5,000 patterns from SD-3 and 5,000 patterns from SD-1. The 60,000 pattern training set contained examples from approximately 250 writers. We made sure that the sets of writers of the training set and test set were disjoint. SD-1 contains 58,527 digit images written by 500 different writers. In contrast to SD-3, where blocks of data from each writer appeared in sequence, the data in SD-1 is scrambled. Writer identities for SD-1 is available and we used this information to unscramble the writers. We then split SD-1 in two: characters written by the first 250 writers went into our new training set. The remaining 250 writers were placed in our test set. Thus we had two sets with nearly 30,000 examples each. The new training set was completed with enough examples from SD-3, starting at pattern # 0, to make a full set of 60,000 training patterns. Similarly, the new test set was completed with SD-3 examples starting at pattern # 35,000 to make a full set with 60,000 test patterns. Only a subset of 10,000 test images (5,000 from SD-1 and 5,000 from SD-3) is available on this site. The full 60,000 sample training set is available.\\n\\nDownloaded from openml.org.\",\n",
       " 'details': {'id': '554',\n",
       "  'name': 'mnist_784',\n",
       "  'version': '1',\n",
       "  'format': 'ARFF',\n",
       "  'upload_date': '2014-09-29T03:28:38',\n",
       "  'licence': 'Public',\n",
       "  'url': 'https://www.openml.org/data/v1/download/52667/mnist_784.arff',\n",
       "  'file_id': '52667',\n",
       "  'default_target_attribute': 'class',\n",
       "  'tag': ['AzurePilot',\n",
       "   'OpenML-CC18',\n",
       "   'OpenML100',\n",
       "   'study_1',\n",
       "   'study_123',\n",
       "   'study_41',\n",
       "   'study_99',\n",
       "   'vision'],\n",
       "  'visibility': 'public',\n",
       "  'status': 'active',\n",
       "  'processing_date': '2020-11-20 20:12:09',\n",
       "  'md5_checksum': '0298d579eb1b86163de7723944c7e495'},\n",
       " 'categories': {},\n",
       " 'url': 'https://www.openml.org/d/554'}"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "from sklearn.datasets import fetch_openml  \n",
    "mnist_data = fetch_openml(\"mnist_784\",data_home = \"./\")\n",
    "# mnist = fetch_openml('mnist_784', version=1, cache=True)\n",
    "mnist_data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'C:\\\\Users\\\\Administrator\\\\traning_python\\\\8800'"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import os\n",
    "os.getcwd()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 'DESCR'数据集描述\n",
    "# data包含一个数组，每个实例为一行，每个特征为一列\n",
    "# target包含一个带有标签的数组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(70000, 784)"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X , y = mnist_data[\"data\"], mnist_data[\"target\"]\n",
    "X.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(70000,)"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline \n",
    "import matplotlib \n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "some_digit = X[36000]\n",
    "some_digit_image = some_digit.reshape(28,28)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([  0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   4., 149.,\n",
       "       255., 184.,  12.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,  11., 133., 212., 253., 253., 253., 102.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0., 162., 236., 253., 253.,\n",
       "       253., 253., 253.,  55.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "        35., 196., 253., 253., 253., 253., 253., 253., 239.,  18.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,  89., 249., 253., 253., 253., 185.,\n",
       "       253., 253., 177.,  24.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0., 129.,\n",
       "       247., 253., 253., 165., 150., 205., 253., 139.,   3.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,  89., 247., 253., 240., 131.,  85., 221.,\n",
       "       253., 253.,  84.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   4., 187.,\n",
       "       253., 253., 236., 139., 252., 253., 253., 253.,  84.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,  21., 253., 253., 253., 253., 253., 253.,\n",
       "       253., 253., 248.,  53.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,  99.,\n",
       "       253., 253., 253., 253., 253., 214., 253., 253., 179.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   4., 186., 251., 253., 249., 172.,\n",
       "       133., 253., 253., 137.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,  49.,  94.,   6.,   0., 212., 253., 253.,  39.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "       126., 253., 253., 197.,   6.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,  27., 234., 253., 253.,  94.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "       100., 253., 253., 239.,  11.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,  61., 249., 253., 253.,  79.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   5.,\n",
       "       109., 253., 253., 193.,   4.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,  66., 253., 253., 253.,  30.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "       147., 253., 253., 182.,   2.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,  99., 248., 253., 222.,  13.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,\n",
       "         0.,   0.,   0.])"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "some_digit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(some_digit_image, cmap = matplotlib.cm.binary)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'9'"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y[36000]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 建立测试集和训练集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "X_train , X_test, y_train ,y_test = X[:60000] , X[60000:] , y[:60000], y[60000:]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "numpy.ndarray"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(y_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([30129, 45297, 21988, ..., 20740, 57980, 43788])"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 将数据集合交叉洗牌，交叉验证时，每个子集数据分布均匀，有些机器学习算法对训练集实例的顺序敏感\n",
    "import numpy as np\n",
    "shuffle_index = np.random.permutation(60000)\n",
    "shuffle_index"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0., 0., 0., ..., 0., 0., 0.],\n",
       "       [0., 0., 0., ..., 0., 0., 0.],\n",
       "       [0., 0., 0., ..., 0., 0., 0.],\n",
       "       ...,\n",
       "       [0., 0., 0., ..., 0., 0., 0.],\n",
       "       [0., 0., 0., ..., 0., 0., 0.],\n",
       "       [0., 0., 0., ..., 0., 0., 0.]])"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_train ,y_train = X_train[shuffle_index], y_train[shuffle_index]\n",
    "X_train"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "numpy.ndarray"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(y_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 训练一个二元分类器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([False, False, False, ..., False, False, False])"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 识别数字5，二元分类5或者非5\n",
    "# 创建目标向量\n",
    "y_train_5 = (y_train == \"5\" )\n",
    "y_train_5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[False, False, False, ..., False,  True, False],\n",
       "       [False, False,  True, ..., False, False, False],\n",
       "       [False, False, False, ..., False, False, False],\n",
       "       ...,\n",
       "       [False, False, False, ..., False,  True, False],\n",
       "       [False, False, False, ..., False, False, False],\n",
       "       [False,  True, False, ..., False, False, False]])"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_train_5.reshape(20,-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_test_5 = (y_test == 5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([False])"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# SGD梯度下降分类器，适合非常大的数据集，独立处理训练集数据，一次一个，适合在线学习\n",
    "from sklearn.linear_model import SGDClassifier\n",
    "\n",
    "sgd_clf = SGDClassifier(random_state = 42)\n",
    "sgd_clf.fit( X_train , y_train_5)\n",
    "\n",
    "sgd_clf.predict([some_digit])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 性能考核\n",
    "## 使用交叉验证测量精度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.96755, 0.9292 , 0.9672 ])"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 评估分类器比评估回归需要困难得多\n",
    "\n",
    "# 3个折叠，正确率达到95%以上\n",
    "\n",
    "from sklearn.model_selection import cross_val_score\n",
    "cross_val_score(sgd_clf, X_train, y_train_5, cv = 3,scoring = \"accuracy\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 把每张图都分成非5\n",
    "\n",
    "from sklearn.base import BaseEstimator\n",
    "class Never5Classifier(BaseEstimator):\n",
    "    def fit(self, X, y = None):\n",
    "        pass\n",
    "    def predict(self , X):\n",
    "        return np.zeros((len(X),1),dtype = bool)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[False],\n",
       "       [False],\n",
       "       [False],\n",
       "       ...,\n",
       "       [False],\n",
       "       [False],\n",
       "       [False]])"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.zeros((len(X),1),dtype = bool)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.9093 , 0.90995, 0.9097 ])"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "never_5_clf = Never5Classifier()\n",
    "cross_val_score(never_5_clf, X_train, y_train_5,cv=3,scoring = \"accuracy\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 准确率超过90%，因为5的图像大约只有10%，你猜一张图不是5，90%的概率你是正确的\n",
    "## 这说明准确率无法成为分类器的首要性指标，特别是当你处理偏科数据集，某些类比其他类更为频繁"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 混淆矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([False, False, False, ..., False, False, False])"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 评估分类器性能更好的方法是混淆矩阵\n",
    "# A类别实例被分为B类别的次数\n",
    "# 想要知道分类器将数字3和数字5混淆多少次，通过混淆矩阵的5行3列\n",
    "\n",
    "from sklearn.model_selection import cross_val_predict\n",
    "\n",
    "y_train_pred = cross_val_predict(sgd_clf, X_train, y_train_5,cv=3)\n",
    "\n",
    "y_train_pred"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 与cross_val_score相比\n",
    "## 同样执行交叉验证\n",
    "## 返回的不是评估分数，是每个折叠的预测\n",
    "## 每一个实例在模型预测时使用的数据，在训练期间从未有过"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[52767,  1812],\n",
       "       [  909,  4512]], dtype=int64)"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.metrics import confusion_matrix\n",
    "\n",
    "confusion_matrix(y_train_5, y_train_pred)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 行表示实际类比，列表示预测类别\n",
    "# 第一行 第一列 53272被正确分为 非5 ，真负类\n",
    "# 第一行 第二列 1307被正确分为 5 ，假正类\n",
    "# 第二行 第一列 1077被正确分为 非5 ，真负类\n",
    "# 第二行 第二列 4344被正确分为 5 ，假正类\n",
    "# 这种衡量方式太复杂，我们可以用更简单的指标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[54579,     0],\n",
       "       [    0,  5421]], dtype=int64)"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_train_perfect_predictions = y_train_5\n",
    "confusion_matrix(y_train_5, y_train_perfect_predictions)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 正类预测的准确率被称为分类器的精度\n",
    "\n",
    "# 精度 = TP / (TP + FP)\n",
    "# TP时真正类的数量 ，  FP是假正类的数量\n",
    "\n",
    "# 召回率TPR = TP /(TP  +  FN)\n",
    "# FN 是假负类的数量\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 精度和召回率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.713472485768501"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.metrics import precision_score, recall_score\n",
    "precision_score(y_train_5, y_train_pred) # 4327 / (4327+ 1276)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.8323187603763144"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "recall_score(y_train_5, y_train_pred)  # 4327/(4327+1094)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 说明检测一张图的时候，只有的%概率是准确的，而且只有%的数字5被检测出来\n",
    "# 精度和召回率合成单一指标，成为F1分数，谐波平均数\n",
    "# 平均值平等对待所有的值，谐波平均值会给与较低值更高的权重，只有召回率和精度都很高时，才能获得较高的F1分数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.7683269476372926"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.metrics import f1_score\n",
    "f1_score(y_train_5 , y_train_pred)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [],
   "source": [
    "# F1分数对哪些具有相近精度和召回率的分类器更有利，这不一定符合你的期望\n",
    "# 有时候你更关系精度，有时候你更关系召回率\n",
    "# 训练一个分类器检测儿童可以放心观看的视频，你可能要求拦截了很多好的视频，低召回率，保留下来的都是安全的视频,高精度\n",
    "# 不能同时增加精度并减少召回率，反之亦然"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 精度与召回率权衡"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 提高阈值，精度提高，召回率降低；\n",
    "# 降低阈值，精度降低，召回率提高"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\Anaconda\\anaconda\\lib\\site-packages\\sklearn\\linear_model\\_logistic.py:940: ConvergenceWarning: lbfgs failed to converge (status=1):\n",
      "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n",
      "\n",
      "Increase the number of iterations (max_iter) or scale the data as shown in:\n",
      "    https://scikit-learn.org/stable/modules/preprocessing.html\n",
      "Please also refer to the documentation for alternative solver options:\n",
      "    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n",
      "  extra_warning_msg=_LOGISTIC_SOLVER_CONVERGENCE_MSG)\n"
     ]
    }
   ],
   "source": [
    "# 如何设置阈值\n",
    "\n",
    "# 用predict_proba得到每个实例属于正类的概率，然后对概率切一下，以LogisticRegression为例\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "\n",
    "clf = LogisticRegression()\n",
    "clf.fit(X_train, y_train)\n",
    "pre_proba = clf.predict_proba(X_test)[:,1]\n",
    "threshold = 0.75 # 阈值设置为0.75\n",
    "pred_label = pre_proba > threshold\n",
    "\n",
    "# pred_proba是每个实例为真的概率\n",
    "# 假设阈值为0.75\n",
    "# pred_label里的True就是概率大于0.75的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 返回决策值decision_function\n",
    "y_scores = sgd_clf.decision_function([some_digit])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "threshold = 0\n",
    "y_some_digit_pred = (y_scores > threshold )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([False])"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_some_digit_pred"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([False])"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#  提高阈值可以降低召回率，提高阈值到200000，就错了这个图\n",
    "threshold = 200000\n",
    "y_some_digit_pred = (y_scores > threshold )\n",
    "y_some_digit_pred"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 如何决定使用什么阈值\n",
    "# 返回决策值，而不是预测结果\n",
    "\n",
    "y_scores = cross_val_predict(sgd_clf ,X_train, y_train_5,cv=3,\n",
    "                            method = \"decision_function\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(60000,)"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 有了y_scores，可以计算所有可能的阈值的精度和召回率\n",
    "y_scores.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.metrics import precision_recall_curve\n",
    "\n",
    "precisions ,recalls , thresholds = precision_recall_curve(y_train_5,y_scores)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAeMAAAEPCAYAAABx8azBAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAgAElEQVR4nO3deXxU1f3/8dcnO4QtSIRAWFzYXFAxWFegFgWXL2h/rihFS0WpG7a21W9bRWhtK1+tG21l+6pVi9YFqNov1SqgFa3BCi6IAsq+hx0CWc7vj3uTTMIkmcAkd5L7fj4e85i5556Z+7mz5JNz7rnnmnMOERERCU5S0AGIiIiEnZKxiIhIwJSMRUREAqZkLCIiEjAlYxERkYApGYuIiASs1mRsZtPNbJOZfVrNejOzR81smZktNrO+8Q9TRESk6YqlZfwkMKSG9RcA3f3baOCPhx+WiIhIeNSajJ1z84GCGqoMA552nveBNmaWE68ARUREmrqUOLxGJ2B1xPIav2x91YpmNhqv9UxmZuapvXr1isPmRRLLul3rWL/roK8/AKnJqfRp36d8edHGRRSXFEetm9Myh44tOwKwvXA7ywuWV7vNPu37kJqcCsC+on2kp6STZPEbElJYCJ99VrGclgYnnhi3lxcJhYULF25xzmVHWxePZGxRyqLOsemcmwxMBsjLy3P5+flx2LxIYvl4w8cs3riYktISSlwJpa4U5xwOR/PU5nzvpO+V152ycAp7i/Z6dXDl9ZxznNXlLM7sfCYAX279kr988hf2Fe+jqKSIotIi9hXtY9PeTewt2ss/rv0HZoZzjmMfO5Z1+9Zx22m3cfc5d5ORknFI+1FYCH/9K6Snw5AhMHt2xboWLeCSSw7rbRIJHTNbWe26WOamNrNuwKvOuROirHsCmOuc+4u/vBQY6JyL3jTwKRmLxN/G3Rs5dfKprN21FoCT2p/EGyPeIDsz6j/jNdqyBbKz4YgjvMcicnjMbKFzLi/aunj0Y80GvuePqj4d2FFbIhaR+tG+RXtW37GaWVfNol3zdizauIiRM0fW6TX27IHdu+spQBGJKpZTm/4CLAB6mtkaMxtlZjeZ2U1+ldeBFcAyYArww3qLVkRqZWYM7TmUedfNI8mS+Puyv/Pal6/F9NyiIujRA7p0gdLSeg5URMrVeszYOXd1LesdcHPcIhKRuDgu+zjGDxzPL97+Bb94+xdc1OOig+o4B3/8I/TqBd/5TuV1X37p3Vu0USEiElfxGMAlIgnqJ2f9hBXbVjDh3AlR1z/+ONx2W/TnLlhQj4GJSCVKxiJNWFpyGlOHTsWqad7+6lfVP/eDD7x7tYxF6l9CJ+MdO3awZcsWDhw4EHQo0sCSk5Np2bIlbdu2JT09PehwGrXqEjHApk3Ry5s1g0mT4KWX6ikoEakkYZNxYWEhGzduJDc3l2bNmtX4B0WaFuccRUVF7Ny5k1WrVtGlSxcl5MN006s3sWTLEv529d9old4KqDgmHM1558GRR3ojq0Wk/iXsVZs2b95MdnY2zZs3VyIOGTMjLS2Ndu3akZWVRUFBTbOxSizmr5zP/JXzWbFtRXnZKadUrC8q8gZzNWvmLc+e7XVPN2/u3USkfiVsMi4sLKRFixZBhyEBa9WqFbt27Qo6jEavd3ZvABZtWFReFtkFneL3kT30UEXZmWfCxx83RHQikrDJuLi4mJSUhO1FlwaSmppKSUlJ0GE0eie3PxmAJVuWlJddcIF3vzJigr4bb4Tly+HSS73R1KecomkvRRpCwiZjqHngiYSDvgPx0bl1ZwBW7/Su6RLZ2RB5ON4Mjj4ajj22oqxsVLWI1J+ETsYiEh9HZx0NwDfbvwHgb3+rWNe+/cH1I5OxiNQ/JWOREOjQogNA+aUdf/Sjmuu3aVPxWJ0TIvVPyTikunXrxnXXXRdz/W+++QYz48knn6y3mKT+dGzZkUt6XcIlvbwDwBs31lw/N7cBghKRchohFVKvvPIKrVq1irl+Tk4OCxYs4JhjjqnHqKS+tEhrwStXvlK+PHAgzJ0LP/5x9Pq9ejVIWCLiUzJuBPbv3x/3SS9OiTzJNAbp6emcfvrpcY1BgvOPf3ijqKs7NpyZCSef7J3apG5qkfqnbuoGNG7cOMyMTz75hG9/+9s0b96cnJwc7rnnHkr969XNnTsXM+Pll1/mhhtuIDs7m/YRI2wWLVrE0KFDycrKolmzZpx11lm88847B21r3rx5nHfeebRu3ZrMzExOOukkpk2bVr6+ajf1hg0bGDlyJB07diQ9PZ2cnBwuvvhiNvnzJVbXTf3MM89w0kknkZGRQbt27RgxYgTr11e+nHW3bt249tprmTFjBr179yYzM5O8vDzefffdw31LpQ427N7AwnULKdhXwKZNNU/mkZ4O//wnXHstfPe7DRejSFg1umRsVv1t8uSKepMn11w30qmnVl9v9OiKegsXxmcfLrnkEgYNGsTMmTMZPnw4EyZMYPz48ZXq3HrrrTjn+POf/1yeAD/66CPOPPNMCgoKmDJlCi+99BJHHHEEgwYNYmFEcLNmzeI73/kOBw4c4IknnmDWrFl8//vfZ2XkCaVVjBgxggULFjBx4kTeeOMNHn30UXJzc9m7d2+1z5k8eTIjRoygd+/evPzyy/z2t79lzpw5DBgwgN1Vrk7/zjvv8OCDDzJhwgSef/55SkpKuPjii9m+ffshvINyKMa8Noa8KXn8c8Vb5OZCp041X7O4bVv485/hsccaLkaRsFI3dQBuuOEG7rrrLgDOP/98du7cyYMPPsjYsWPL65x22mlMnTq10vN+8pOf0KVLF9566y3S0tIAGDx4MCeccAITJkxg5syZOOe4/fbbOfnkk3n77bdJSvL+3xo0aFCNMS1YsID777+fa665przs8ssvr7Z+SUkJv/zlLxk4cCAzZswoL+/VqxfnnHMO06dP57aIa/Pt3LmTjz/+mKysLAA6dOhAv379eP311xk+fHiNsUl8ZDfPBmBNwZbysqQa/h1fvx6+/tobzNWlS31HJxJuja5l7Fz1t8hW7OjRNdeNtHBh9fUiW9unnhqffbjiiisqLV911VXs3r2bTz/9tLzs0ksvrVRn3759zJs3j8svv5ykpCSKi4spLi7GOcegQYOYP38+AEuXLmXlypX84Ac/KE/EsejXrx8TJ07kkUce4ZNPPsFVfZOqWLp0KZs2baqUvAHOPvtsunbtyrx58yqVn3HGGeWJGODEE08EYNWqVTHHKIendXprANZuja034oEH4Kyz4J576jMqEYFGmIybgvZVZlkoW167dm15WU5OTqU6BQUFlJSUMGHCBFJTUyvdHn/8cbZt20ZpaSlbt24FILeO56Y8//zzDB06lAceeIA+ffrQqVMnxo8fX34su6qyizdUjRO8Vm/Vizu0bdu20nLZgLTCwsI6xSmHLquZ98/Qyo2xJeOyi0Y89VR9RSQiZdRNHYCNGzdy9NFHV1oG6NSpE8XFxcDB00C2adOGpKQkbr75Zr73ve9Ffd2kpCTatWsHVE7ssTjyyCOZNGkSkyZNYunSpTz11FPce++9ZGdnM2bMmIPqlyXXDRs2HLRuw4YN5OXl1Wn7Uv/KWsYff7Ejpvpdu9ZnNCISSS3jALzwwguVlmfMmEGLFi044YQTqn1OZmYm55xzDosWLaJv377k5eUddAPo0aMH3bp1Y+rUqbV2NVenZ8+e3H///WRlZVXqOq9ap3379pWOFwO89957rFy5kgEDBhzStqX+tG3m/QOV1dHrtajtlPGMjPqOSETKqGUcgClTplBaWkq/fv2YM2cOU6dOZdy4cbSJnIMwioceeoj+/fszePBgRo0aRU5ODlu2bOGjjz6ipKSE3/72t5gZDz/8MN/97nc599xzuemmm8jOzmbJkiVs2rSJ++6776DX3bFjB4MGDeKaa66hV69epKamMmvWLLZt28b5558fNZbk5GTGjx/PjTfeyLXXXsu1117L2rVr+fnPf0737t25/vrr4/JeSfxkZ3oDuLYXeaerVfPRlqvDkAMROUxKxgGYNWsWt956KxMmTKB169b84he/4Je//GWtz+vbty8ffvgh9913H7fddhs7duwgOzubvn37ctNNN5XXGzZsGG+88QYTJkxg1KhRABxzzDGVRmtHysjIoG/fvkyZMoWVK1eSlJREz549efbZZxk2bFi18YwePZrmzZszceJEhg0bRosWLbjwwgt54IEHdC3qBNSvYz8WjFpAYUE2W3vW3g2tZCzScOxQuzIPV15ensvPz692/ZIlS+jdu3cDRlT/xo0bx3333UdRUZGu1VwHTfG70Bj85S9QdtZZQH8mRJoUM1vonIs6oEb/+4qEzIED8OmntSfYPn0aJh4RUTIWCY2ikiJuef0Wcn/4A048EaqMIzzIMcfA/PnwwQcNE59ImCkZN6Bx48bhnFMXtQQiJSmFP+b/kc2dp0FSMVGmNK8kIwPOOQdOO61h4hMJMyVjkZAws/JzjUnfwRln1Fx/9WoYMQL8mVtFpB4pGYuESOsMPxlnbKdDh5rrLl8OzzwDv/td/cclEnZKxiIhkpma6T1I3UuUydMq2bWr/uMREY+SsUiINE/1L2KctodvfavmujrPWKTh6OcmEiKZaRUt47ILQVQnyjVARKSeaFivSIickH0CXyzfyynnZdCqVc11+/aFRx+F445rmNhEwkzJWCREHrvwMR67MPb6t95af7GISAV1U4fQ3LlzMTPmzp1bXjZw4EAGDhwYWEwiImGmZCwSIkVF8LfXinlr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\n",
      "text/plain": [
       "<Figure size 576x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 使用matplotlib绘制精度和召回相对于阈值的函数图\n",
    "\n",
    "def plot_precision_recall_vs_threshold(precisions ,recalls,thresholds):\n",
    "    plt.plot(thresholds,precisions[:-1],\"b--\",label = \"precision\",linewidth=2)\n",
    "    plt.plot(thresholds,recalls[:-1],\"g--\",label = \"recall\",linewidth=2)\n",
    "    plt.xlabel(\"Threshold\",fontsize=16)\n",
    "    plt.legend(loc = \"upper left\", fontsize=16)\n",
    "    plt.ylim([0,1])\n",
    "    \n",
    "plt.figure(figsize=(8,4))\n",
    "plot_precision_recall_vs_threshold(precisions ,recalls,thresholds)\n",
    "plt.xlim([-700000,700000])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 目标设置为90的精度，阈值大概在3wan左右\n",
    "y_train_pred_90 = (y_scores > 30000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.96"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "precision_score(y_train_5, y_train_pred_90)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.004427227448810182"
      ]
     },
     "execution_count": 69,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "recall_score(y_train_5, y_train_pred_90)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 576x432 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.rcParams['font.sans-serif'] = ['SimHei']\n",
    "def plot_precision_vs_recall(precisions, recalls):\n",
    "    plt.plot(recalls, precisions, \"b-\", linewidth=2)\n",
    "    plt.xlabel(\"召回\", fontsize=16)\n",
    "    plt.ylabel(\"精度\", fontsize=16)\n",
    "    plt.axis([0, 1, 0, 1])\n",
    "\n",
    "plt.figure(figsize=(8, 6))\n",
    "plot_precision_vs_recall(precisions, recalls)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 总结\n",
    "# 获得了一个90%精度的分类器，但如果召回率太低，精度再高，也不怎么有用\n",
    "# 如果工作中需要99%的精度，你应该回应召回率多少？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# ROC曲线"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 本质是 真正类率tpr和假正类率fpr（错误的分为正类的负类实例比例\n",
    "# 与召回/精度曲线非常相似"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.metrics import roc_curve\n",
    "\n",
    "fpr,tpr,thresholds = roc_curve(y_train_5,y_scores)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAf0AAAF6CAYAAAATeYHoAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAgAElEQVR4nOzdd3xUVf7/8deZSS8kAUIVKYoiCEEITVAQBLFscVWKFEFR1NXdVb/qqoAsomv7sn7tyyqKuoK4P1d3LYiAYqMFNKKiooD0DultZs7vj5kgIpAAydzMnffz8WAzmblz7ydZ5D2n3HOMtRYRERFxP4/TBYiIiEh4KPRFRESihEJfREQkSij0RUREooRCX0REJEoo9EVERKKEQl9ERCRKhD30jTGNjTEfHeH1WGPMf40xnxhjrgxnbSIiIm4W1tA3xmQAM4HkIxx2I7DCWtsbuNQYkxqW4kRERFwu3C19PzAUyD/CMf2AOaHHHwLZtVyTiIhIVIgJ58WstfkAxpgjHZYMbA493gM0PvgAY8w1wDUAycnJXdu1a1ezhYqISLVV+AMELPgDFn/Asv+feAs/X+jdHvC//OzFgIWich8xHhN82kJxuZ/YGENZRYDKFeNt6E1lvgDGQCSsJG8I5l4gVGyc1wMm+PxPxxjK/QHivB5ivOZn7wUI+CvI37EZf3kpCanplBbs22WtzTzaWsIa+tVUCCQCeUBK6PufsdZOB6YDZGdn25ycnLAWKCJS26y1+4M0YIN/KvyW/JKKYLhaSyBg2ZJXytZ9JcTFeAhYCFi7/72B0NfvthXQMCUeXyDAF5vyaJqWsP+14PHBr6s25dG4XgIeT+i6AagIBPhswz4apsSHzvvT+8p9Acp8gRr7meMP+r5e6GtiNd+fmhCDxxg8BrwegzGGnQVltG6YTHyMB6/H7H9+zfYCerZpgMcYvJ7g8T6/paDUR7umqVgLvkCAVg2SifEYCst8tGoYfOz1ePD5AzRJSyDGEzxvXIwhNSE2dD6D1xjiYjwkxnmP+/dSVFREmzZtSE6IY/oLzzN06FCMMT8ey7nqYuivAPoA/wKygCXOliMi0cZaS1G5n10FZZT7AwSs3R+CpT4/ecUVeD3mZ4G8ZO0ekuO9+APB91cG85eb82iWnrj/2B92FAGwaW8xMV4PSXHen4I0dMze4grHfva1u4oO+fyuwrIq39uuSSrrdxdxWtN6JMV5MRiMCbZyg63dn1q9ld9TeQzBHoM9ReUM6tBkf3AWlPlo2yiFgLWclJlCjDf4vMdjSIz1kpYYS3yMhxiv+25Gq6ioIDY2luTkZB577DG6detG69atj+ucjoa+MaY/0N5a+/gBT88E3jbGnAW0B5Y6UpyIOC6/tIL1u4qo8AfYsKeY9buK2binmLSkWHx+yw87C/GG/vEPWH7WEvUFAixfv5dTGqeEWrLB160NdhFXfr89v4zCMh9pibEEQkFdXO6v4Z9k72Ge95NXcuSAj/EEA85jwGsMReV+TshIJNbrwWOCP9f2/FLaNUmlVcPk/S1djwm2aD0m2Iu+p7Cc05rWI8Zr2FNUTttGKaHzHnh8sEv9hIzE/cFa+Xrjegkkxnn3f28OaFEnxdXF9mNkW7VqFcOGDWPy5MlcdtllDBkypEbO68j/U9bafqGvC4GFB732ozFmIMHW/iRrbU3/1yciNay0wk9ZRQBfIEBxuZ+CUh8V/gBb80ooLvfjC1h8fst32wuonxxHhT/A5xv3cUJGIj6/ZUdBGTsKymiQHMeStbs5sX7SYVucR+vLzUeaN/yTQ4VvZWv+lMYpP3Xbegyb9pbQskESGUlxP+tO/n5HIed3bEpSnHd/kHo9hn3FFbTJTN7fFVzhD9AsPZH4GA/1k+N+FqTeUMAnx8cQ68LWqxyZtZann36am2++mfT0dOrXr1+j56+TH8+stVv4aQa/iByFyq7lwjIfJaEw3lNcfsBr7O+S3p5fSozHQ4U/wPc7CqmXGIvPH+DzjXk0S0/AF7Bszyvl2+0FlPsCZCTFUREIsHZnEakJMfj8lpKKmv9cfnDgN64XT9O0RErK/bSon0iD5HjaNwu2WovKfDRLTyTO6wmGp6eyFWqw1hIf4yU1IfhPXWVr9qevP3U1ZyTF4fGY0JitCZ7Pc8RJxyI1as+ePVx99dW89tprDB48mJkzZ9KoUaMavUadDH0RN/MHLFv2leALWPyBAHklFZRVBFvIW/NKSIj9aYzXH7AUlfnYmldKfkkFvoAlLiY4iWj5+r1szy+lSVoCm/aWEOutHGOuvdp3FPw0rltQ6vvF6/WT44jxGHYUlNGxeRoJsR4yU+NJioshxhOcvVxU5qdt4xQMhjKfn1YNkoOTqALBDxX1EmOJi/GQmRJPw5T4GpkIJRIJ5s+fz3/+8x8efvhhbrrpJjyemu/pUeiLVKG4PBi663YWsTW/FKzFF7Cs3ppP/eT4/ZO8/AHLyg17aZAc94tZ0QFr2ZpXyo+7i2u8vk17SwCo8P+U9pVjvQAnZCSyaW8JbTKTSU+MDXUlh1rEGDbsKaZbqwy8Hg/b80vJapGGxxiKyvyhLmmDL2DJSIqjZYMkEmI9xHg8JMfHkBTnJcZriPWoVSxyLPx+P7m5uXTp0oUhQ4aQnZ1NmzZtau16Cn2JSqUVfhZ+s4P1u4sorQiw6NsdpCXFsbuwjK+2BMeA6yfHsaeovNZqOLF+ErFeQ4zHw5odBfQ+uSEl5X48HkPL+kn7by3yeqCkPEBCrIeU+BhOqJ9EcpwXbyhk2zWpR73EGDKS4vZ3TVexFoaI1AGbN29m5MiRLFmyhG+//ZYTTzyxVgMfFPoS4XYVlrFqcx6fb9iHN9R9XOEPkLsxLzhJLNQC/2zDXjbvK+GEjCTWVXOC2KECv01mMgkxXrJbZRDn9bCjoIz2zertn+nsNcFFQ05pnLp/xvWB48geYzilcQppibEKZpEo9uabbzJmzBhKSkp46qmnaNGiRViuq9CXOqW43MfOgjJ+3F2MP2DZW1zOnqJyPlqzi7gYD6s25ZEY5612cB/sUO/7TedmNEtPpMIXoFvr+sTFeGiWlkjDlDgAkuJiNK4sIjXCWsvNN9/MI488QufOnZk9ezannnpq2K6v0Jew2bKvhM837iNgLWt3FpFfUsF3OwpJivUy96ttx3Xu+BgPpzZJ5ay2DUmICQZ0mS/AiQ2S8BpDjDfYC9C2USppibGkJsSQnhRXEz+WiEi1GWPwer384Q9/4IEHHiAhISGs11foS60o8/lZvm4vLy/7kcU/7D6mFcYaJMfRpWUG+SUVNK4X/A+j7ymZNEyNJyMplib1EoKzxXUvs4jUYdZaXnjhBdq2bcuZZ57JQw895NjwnkJfjtmuwjJy1u9h8Q+7KSj1UVTu472vt1d5y1jrhslknZBGQqyX5umJJMR6ads4hbaNU2lSL2H/BDURkUhXUFDAddddxz//+U9GjRrFmWee6eh8HoW+VMnnD7B5Xwlb80pZv6uIl5b+yHfbCin3V2+jjct7nMig9o3JblWflHj9lROR6JCTk8OwYcNYt24d99xzD3fccYfTJSn0JSivuILl6/ewems+W/NL+e/nWzi5cQqfbdhX5XtbNUiibeNUBrZvTKPUeE5vnkZaYqyWEBWRqLVs2TL69OlDkyZNWLRoEX369HG6JEChH3UWfbeTd1ZtZfbyjTSpl4DfWnYWHHr3rIMD/6TMZDbsKaZH6wZktUjjun4nq+UuInKAQCCAx+Oha9euTJgwgRtuuKHG188/HvoX28WstXyxKY8la3fz/Kfr2ZpX+rPXt+WXHvJ9v+ncjJYNkmlcL56sE9JpmBJPk7TwzjAVEYk08+fP5+abb2bu3Lk0a9aMSZMmOV3SLyj0XSIQsOwqKuP7HYU8/O63rKyiW/6yrifQ66QG9GjTgFivITMlXovFiIgcg4qKCiZNmsQDDzxAu3btyM/Pp1mzZk6XdUgK/QiUV1zBojU7WbeziH98tJbCsl9ufHKgpDgv/U7NpHG9BP7Qvy0Zybo/XUSkJqxbt47hw4ezdOlSrr76ah555BGSkpKcLuuwFPoRZPn6PUx64ytWbz3y/uDdWmXQ66SGDMk+gRMy6u5fPhGRSDdlyhS++eYbXnnlFYYMGeJ0OVUy1tbiPpxhkJ2dbXNycpwuo9bkbtzHvW+tZtn6Pb94LTM1nrPaNuSUxqlcfEZzGqWqi15EpLYVFxezZ88eTjjhBPbt28fevXtp3bp1WGswxqyw1mYf7fvU0q9jfP4A/1qxiT+/tuqwxzx4aSeGZIdncwYREfnJqlWrGDp0KMnJySxdupT09HTS09OdLqvaFPp1wI78Uh5//3s+27CPVZvzfvF68/REzj4lk+v7nUSL+uquFxEJN2stTz/9NDfddBMZGRk8+uijeDyRtxaJQt9BP+wsZMD/LjrkaynxMdw88BRG9mxJXEzk/cUSEXGLvLw8xo4dy7///W8GDx7MzJkzadSokdNlHROFvgO25ZXy59e+4INvd/7s+R6t6/PAJZ1o2SBJY/MiInVEXFwcP/74Iw8//DA33XRTRLbwKyn0w+jLzXnc+9ZqFq/dvf+5kxulcNeFp3HOqZH5qVFExI38fj+PP/44V155JampqSxdupSYmMiPzMj/Ceo4ay0jn13KZxv2UVzu/9lrd/+qPWN7h3fGp4iIHNmmTZsYOXIkixYtIiEhgfHjx7si8EGhX2s+XrOLJWt38/j73//s+Rb1E+nYPI1Hhp6hsXoRkTrmv//9L2PHjqW0tJTnn3+e0aNHO11SjVLo17B5X23jmhdX/OL5nm3qM310NvUSYh2oSkREqvLEE09www03cMYZZzBr1ixOPfVUp0uqcQr9GvS/877lsYU/texjvYY/nXsKHZuncfYpmQ5WJiIiVbnooovYsGEDU6ZMIT4+3ulyaoVW5KsBc5Zv5Lb/98XPnnv9973p3CJyFmwQEYk21lpmzpzJO++8w6xZsyJqVv6xrsgXOT9hHWSt5YaXV/4s8M9q25B1f71AgS8iUofl5+czcuRIxo4dy44dOygsLHS6pLBQ9/5xGPXsMj7+fhcADVPi+e+NvWmaluhwVSIiciTLly9n+PDhrF+/nnvuuYc77rgDr9frdFlhodA/BtZaJr7x5f7A79+uETPGdHO4KhERqUpFRQVDhgwhEAiwaNEievfu7XRJYaXQP0qLf9jNXf9exdpdRQCceVIDBb6ISB23c+dOMjIyiI2N5d///jctW7YkIyPD6bLCTmP61VRa4eeypz9l+D+W7A/8a/uexMtX93S4MhEROZL33nuPjh07MmXKFAA6d+4clYEPaulXy67CMrKnzv/Zc/+6thfZreo7VJGIiFSloqKCiRMn8uCDD9KuXTsuu+wyp0tynEK/CnuKyn8W+MO6teD+Szo5WJGIiFRl3bp1DB8+nKVLl3L11VfzyCOPkJSkrckV+lUYPWPp/scTL2rPVX20Vr6ISF23d+9e1q1bx5w5c9TCP4DG9I/gyQ++58vN+QD85dcdFPgiInVYUVER//znPwHo0qUL69atU+AfRKF/GI8vXMODc78F4IwT07nizFbOFiQiIof1xRdfkJ2dzahRo/jqq68A1J1/CAr9Q1i7s5CH5323//tZmqEvIlInWWt58skn6d69O/v27eO9996jQ4cOTpdVZ2lM/yDfbS9g0N8+3P/9kjsGkBAbHSs1iYhEmjFjxvDCCy9w/vnn8/zzz9OoUSOnS6rTFPoHKPP5fxb4b97YhyZpCQ5WJCIiRzJo0CCysrL405/+FFEb5jhFoX+AUyfM3f/4/113Jqc3T3OwGhEROZjf7+fee++ladOmXH311YwYMcLpkiKKPhaFvLNq6/7HD17Sia4to3O1JhGRumrTpk0MGDCAu+++m+XLlztdTkRSSx+Y99U2rvvnSiC4W96Qbi0crkhERA70n//8h7Fjx1JWVsbMmTMZPXq00yVFpKgP/aVrd3PNiyv2f7/glr4OViMiIgdbvXo1v/3tb+ncuTOzZ8/mlFNOcbqkiBX1of9/C9bsf/zx7eeQlhjrYDUiIlIpLy+PtLQ0TjvtNP79738zePBg4uPjnS4rokX1mP6eonKWrN0NwP+7rhcnZGghBxERp1lref7552nZsiWffvopAL/5zW8U+DUgqkP/9/9cScDCaU3r0bWldswTEXFafn4+I0aMYOzYsZxxxhm0bNnS6ZJcJWpDf92uIhaHWvlDs09wuBoREVm+fDlnnHEGc+bMYerUqcyfP5/mzZs7XZarRO2Y/oG752ldfRER57333nv4fD4WLVpE7969nS7HlaKypb8tr5SNe0oAmDO+F8YYhysSEYlO27dvZ/HixQDcfvvt5ObmKvBrUVS29O9562sAmtRLoHtrjeWLiDhh3rx5jB49mri4OL7//nvi4uJIT093uixXi8qW/ltfBFffu3mQ7vUUEQm3iooK/vznP3PeeefRoEED3nrrLeLi4pwuKypEXUv/+x0F+x//qlMzBysREYk++fn5DBo0iKVLl3LNNdfwt7/9Tfveh1HUtfRfXroRgD4nNyQxTlvmioiEU2pqKqeffjpz5szh73//uwI/zKIu9D/4dgcAV/Vp7XAlIiLRoaioiN///vesWbMGYwzPPPMMl112mdNlRaWo6t7/fkcBa3cV4fUYep3UwOlyRERc74svvmDo0KF8++23dOrUibZt2zpdUlSLqpb+snV7ATilcSoJseraFxGpLdZannjiCbp3705eXh7z589n/PjxTpcV9cIe+saYZ40xi40xEw7zeoYx5m1jTI4x5u81ee1XVwTH8y/q1LQmTysiIgf5+9//zg033MCAAQPIzc2lf//+TpckhDn0jTG/A7zW2l5AG2PMofp5RgH/tNZmA6nGmOyauLa1lg27iwHo1kr35ouI1IaysjIArrjiCp599lnefPNNMjMzHa5KKoW7pd8PmBN6PA/oc4hjdgOnG2PSgRbAxpq48MJvdrC7qJyMpFi6tsyoiVOKiEiI3+/nL3/5C507d6agoIDExESuvPJKrXhax4Q79JOBzaHHe4DGhzjmY6Al8Adgdei4nzHGXBPq/s/ZuXNntS785Ac/ANDlxAy8Hv0lFBGpKZs2baJ///5MnjyZ7Owa6ZyVWhLu0C8EEkOPUw5z/buBa621U4BvgLEHH2CtnW6tzbbWZlen26jCH2DFj8FJfOPOanOMpYuIyMHeeOMNsrKyWLFiBTNnzuTFF18kNTXV6bLkMMId+iv4qUs/C1h/iGMygI7GGC/QA7DHe9EFq3fsf9yzjcbzRURqQiAQ4KGHHqJly5asXLmS0aNHO12SVCHc9+m/DnxkjGkGnA8MM8ZMtdYeOJP/r8BzBLv4FwOzjveiMz9dDwRX4dP4kojI8fnmm29o0KABmZmZvPbaa6SlpREfH+90WVINYW3pW2vzCU7mWwKcY63NPSjwsdYus9Z2sNamWGsHWmsLj/e6q7flA3BaU3U5iYgcK2stM2bMoGvXrtx8880ANGrUSIEfQcJ+n761dq+1do61dls4rpdXUsG+4goAxvc9KRyXFBFxnby8PC6//HKuuuoqevTowQMPPOB0SXIMXL8i39urgtvoJsV5aZiiT6MiIkfrq6++okuXLrz66qtMnTqV9957j2bNtEtpJHL92vsb9wQX5DmxvnZyEhE5Fo0aNaJx48a8+OKLnHnmmU6XI8fB9S39Nz7fAsDVulVPRKTatm/fzm233YbP5yMzM5NPPvlEge8Crg/9Mp8fgM4npjtciYhIZJg3bx6dOnXiscceY+XKlQC688klXB36BaUV7CosJ8ZjaN0g2elyRETqtPLycm677TbOO+88MjMzWb58Od27d3e6LKlBrh7T//SH3QA0So3Ho6V3RUSOaOzYsbz88suMHz+eadOmkZSkuVBu4+rQr5zElxzv6h9TROS4+P1+vF4vt9xyC7/73e+45JJLnC5Jaomr03DtriIAhnZr4XAlIiJ1T1FREX/4wx+Ii4vjqaeeokuXLnTp0sXpsqQWuXpMf9m64AZ9rTSeLyLyM7m5uWRnZ/Pcc89Rv359rD3ubU4kArg69DfvLQGgVUONS4mIQHAp3ccff5wePXqQl5fH/PnzuffeezU7P0q4NvSttZRUBG/Xa5aeWMXRIiLRYfPmzdxxxx0MGDCA3Nxc+vfv73RJEkauHdPfll+6/3FSnGt/TBGRavnyyy/p0KEDJ5xwAsuWLaNdu3Zq3Uch17b0v98R3JyvW6sMhysREXGOz+dj8uTJZGVl8dJLLwFw2mmnKfCjlGubwKu3BrfTbZqmrn0RiU4bN25kxIgRfPTRR4waNYrf/va3TpckDnNt6G/ZF+zeLyzzOVyJiEj4vfXWW4wePZqysjJeeOEFRo0a5XRJUge4NvQLSoNhf1rTVIcrERFxRuvWrZk1axZt27Z1uhSpI1w7pv/f3ODuel1O1Ji+iESH1atX89xzzwFw4YUXsnTpUgW+/IwrQ99aS7k/AEDrhlqYR0TczVrLs88+S3Z2NnfddReFhcGJzF6v1+HKpK5xZehv3hdclCc5zqvQFxFXy8vLY/jw4YwbN46ePXuSk5NDSkqK02VJHeXKMf3PNuwDICHWq9tSRMS1ysrK6N69Oz/88AP33Xcft912m1r3ckSuDP3toYV5slqkO1yJiEjNs9ZijCE+Pp6bbrqJTp06ceaZZzpdlkQAV3bvr9ywF4CTMtW1LyLusm3bNs4//3zeeecdAK699loFvlSbK0N/U2ijncb1EhyuRESk5sybN4+srCwWLVrErl27nC5HIpArQ3/N9uDM1ZMbaTKLiES+8vJybrvtNs477zwyMzPJycnRYjtyTFwZ+gmxwR+rRX1tqSsike+NN97goYce4tprr2X58uV06NDB6ZIkQrlyIl+5L3iPfmZqvMOViIgcuw0bNnDiiSdy6aWX8sknn2jsXo6b61r65b4AReV+vB5DirbUFZEIVFRUxJVXXkmHDh1Yt24dxhgFvtQI16XijoLg7XoZSXF4PLpHX0Qiy+eff86wYcP47rvvuPPOO2nRooXTJYmLuK6lv2F3MQCN66lrX0Qiy+OPP06PHj3Iz89n/vz5TJ06lZgY17XNxEGuC/2icj8Ae4vKHa5EROTorFq1ioEDB5Kbm0v//v2dLkdcyHUfIXcXlgHQ66SGDlciIlK1RYsWUa9ePc444wwee+wxYmNjtXy41BrXtfS/3JIHQHpSrMOViIgcns/n4+6776Z///5MmDABgLi4OAW+1CrXtfTjQptNVN62JyJS12zcuJERI0bw0UcfMXr0aB5//HGnS5Io4brQ35oXXIK3szbbEZE66Msvv+Tss8+moqKCF198kZEjRzpdkkQR13Xvb9kXDH2txicidVG7du0YOnQoK1euVOBL2Lku9HM3Bcf0G6TEOVyJiEjQ6tWrOf/889m1axcxMTE89dRTtG3b1umyJAq5LvST4oJj+hlJCn0RcZa1lmeffZbs7GxWrFjBDz/84HRJEuVcFfoV/gDFofv00xM1e19EnJOXl8fw4cMZN24cvXr1Ijc3lx49ejhdlkQ5V4X+ntCCPPWTtQSviDjr1ltv5V//+hf33Xcf8+bNo2nTpk6XJOKu2fs7C4IL82ToHn0RcUAgECAvL4+MjAzuvfdexo4dS69evZwuS2Q/V4X+vuIKABoka919EQmvbdu2MXr0aIqLi/nggw/IzMwkMzPT6bJEfsZV3fuVO+wFrHW4EhGJJu+++y5ZWVn7F9vxhhYJE6lrXBX6RWU+ANI1c19EwqC8vJxbb72VwYMH06hRI3Jycrjmmmu0lK7UWa4K/c827gOgfdNUhysRkWhQVlbG66+/zrXXXsuyZcvo0KGD0yWJHJGrxvRT44M/TuX2uiIiteGNN95g0KBBpKamsmLFCurVq+d0SSLV4qqW/ueh1fhObayWvojUvMLCQsaOHctvf/tbnnjiCQAFvkQUV7X0GyYHx/LL/dphT0Rq1ueff87QoUNZs2YNEydO5E9/+pPTJYkcNVeFflloO90TtdmOiNSgV155hdGjR9OwYUMWLFjAOeec43RJIsfEVd37ReXB2fuV6++LiNSELl26cPHFF5Obm6vAl4jmqtCvXIY3I1m37InI8Vm0aBF/+MMfsNbStm1bZs+eTcOGDZ0uS+S4uCr0f9xdDEADhb6IHCOfz8fdd99N//79mTt3Lrt373a6JJEa45rQL/f9NHmvXoLW3heRo7dx40bOOeccpkyZwqhRo1i5cqVa9+IqrpnIl1dSsf+xdtgTkaPl9/s599xz2bJlCy+99BIjRoxwuiSRGuea0N9XHBzPT9cOeyJyFEpLS4mNjcXr9TJ9+nSaN2/OySef7HRZIrXCNd37pRW6N19Ejs7q1avp3r07Dz30EAB9+/ZV4IuruSb0dxYGd9g7KTPF4UpEpK6z1vLMM8/QtWtXtm3bRlZWltMliYRF2EPfGPOsMWaxMWZCFcc9aYz51dGef+u+kmMvTkRcLy8vj+HDh3P11Vdz5plnkpuby/nnn+90WSJhEdbQN8b8DvBaa3sBbYwxbQ9z3FlAE2vtf6t77srZ+6c3T6uJUkXEpb7++mtef/117rvvPubNm0fTpk2dLkkkbMLd0u8HzAk9ngf0OfgAY0ws8A9gvTHmN9U98Y6CMgDiY7Uan4j8XCAQYOHChQD06tWL9evXc8cdd+DxuGaEU6Rawv03PhnYHHq8B2h8iGNGA18DDwLdjTE3HnyAMeYaY0yOMSZn586dAFgbfG1XKPxFRAC2bt3KoEGDGDBgACtWrACgSZMmDlcl4oxwh34hkBh6nHKY658BTLfWbgNeAn6x0LW1drq1Nttam52ZmQmALxBM/VYNk2uhbBGJRHPnziUrK4tPP/2Uf/zjH3Tp0sXpkkQcFe7QX8FPXfpZwPpDHPM90Cb0OBv4sTonLglttpOh+/RFBJgwYQLnn38+TZo0IScnh3HjxmGMFu6S6HbcoW+M8YQm3lXH68AoY8w0YAjwlTFm6kHHPAucY4z5ELgeeLg6Jy4s8wOQHO+a9YZE5Di0aNGC66+/nqVLl9K+fXunyxGpE6pMSGNMHFLPUQcAACAASURBVHALcD+QYK0tCT2fAAwlODHvXaDKTeyttfnGmH7AQODBUBd+7kHHFACXHd2PAaUVwdBP0EQ+kaj18ssv4/V6GTp0KOPHj3e6HJE6pzotfQ9wK3AjMOmA518C7gQMUHGI9x2StXavtXZOKPBrzNdb8gFIiNVsXJFoU1hYyJgxYxgxYgQzZ87EVs7sFZGfqU5feDlQBLwN5BhjFgNtCd5+19VaW2yM8ddeidXTLD0BgIJSn8OViEg4ffbZZwwbNow1a9YwceJEJk2apLF7kcOoMvSttQFjTIW19ntjzE3ABuAzYBnwG2PMnCOfITzKQovztMiocpRBRFxi7dq19OzZk8zMTBYuXEi/fv2cLkmkTjvaWW/brLWfG2POAB4F2gOLa76so1c5ph8fo+59Ebfz+XzExMTQpk0b/u///o9LL71U+96LVEO1E9IY0x34f8aYwQRvpVsLbLfWLic4ru+o/FC3fmKcJvKJuNkHH3zAKaecwmeffQbAtddeq8AXqaYjhr4xpqcx5o3Qt58BDxG87W4PwRn2GaHb7xKNMdNCfx4xxjxdq1UfQnF5sKWflqj79EXcyOfzMWnSJPr3709sbKyW0BU5BlV177chuHRuLPBvYDLwR4L30lsgHziJ4IeH1qH3eIGEWqj1iFZv1ex9EbfasGEDI0aM4OOPP2bMmDE89thjpKRoG22Ro3XE0LfWvgy8bIzZRDDgHyAY9gOANwjem38VsMZae3Et13pEjevFsz2/TPfpi7jQc889R25uLi+99BIjRoxwuhyRiFXdZnG5tfZyYC+QBpQClwL1gJYEPwg4qrJ7PzVe3fsiblBSUsLXX38NwJ133skXX3yhwBc5TkfbF/40cBqwm2DXf7a1dkWNV3WUrLUUlWkin4hbfP311/To0YNBgwZRUlJCbGwsrVq1croskYhXZeib4CoX8caY+sBsguP7yQRv2WtUu+VVT7k/QMBCrNcQp1v2RCKWtZbp06eTnZ3N9u3beeaZZ0hMTKz6jSJSLdW5Tz+e4Nj9YGCWtfZLAGPMaOAFY8yZQFztlVi1yoV54mPUyheJVCUlJVxxxRW8+uqrnHvuubz44ova916khlWnWewDbiDYyv9z5ZPW2neAR4AAwQ8GjikJjed7HF8tQESOVXx8PGVlZdx///28++67CnyRWlCdZXh9wD9D3xYd9NpfQ93/XWuhtmqrnMSXr3X3RSJKIBBg2rRpDBkyhBNPPJHXX39d6+aL1KLjHgC3QV/URDHHamdBGQAnZSY7WYaIHIWtW7cyaNAgbr31VmbOnAmgwBepZdUKfWNMvDHmNWNMfOj7hsaYRsaYZGOM3xiTfMCxLxhjetdWwYfiCwTH9PNK1NIXiQTvvPMOWVlZfPrpp/zjH/9gwoQJTpckEhWqWoa38mN3APhN6CvADOBdoILguvtloePrAcOAZrVR7OHkFVcAcHrzeuG8rIgcg9mzZ3PBBRfQpEkTcnJyGDdunFr4ImFSVUv/DWPMr621FQDW2gpjzNUEZ/LfYq0tDz5tK5vYowku4PN6rVV8CEWVY/olFeG8rIgcBWuDa3hdeOGFTJo0iaVLl9K+fXuHqxKJLocNfWOMh+AmO7NCt+dhjGkB/C9wm7V24UHHJwB/Au6u/JAQbulJjt45KCKH8dJLL9GnTx9KSkpITU3lL3/5i+6/F3HAYUPfWhuw1t5NcDe9UaGnHwWWWmsfOcRb/gpsBabXeJVVKK0ItvQb1wv7Pj8icgSFhYWMGTOGUaNG4fF4KCgocLokkahWnVv23gbeNsYEgNuBQgiO99tgf50xxvwv8Fugp7U2cPiz1Y79S/Bqsx2ROuOzzz5j2LBhfP/990yaNImJEycSE1Od9cBEpLYc8b9AY8xcoDj0rQXuBzyhWfz7jDHdQ6/9Cuhlrd1ea5UeQWlF8HNGcrxCX6QusNZy/fXXU1RUxMKFC+nbt6/TJYkIVbf0VxKamU+wJX8a8ArBZXe3AJ8C/wecAEwyxvzRifH8cn+wez9e6+6LOGrXrl3ExMSQnp7Oyy+/TGpqKg0bNnS6LBEJOWJKWmvvtNb+heDkPQhupZsSev5xa+1jBHsAOgPdgH/UarWH8c3W4Dih1t4Xcc77779Pp06duOGGGwBo3bq1Al+kjqnOLnt/BeYTDPezgBHGmBsOPMZa+x3B+/jPN8b8ujYKPZImacEJfLuLysN9aZGo5/P5mDhxIgMGDKBevXr8z//8j9MlichhVLU4z83AOOCPANbatcAI4K/GmDaVh4Ve20JwzP/uWqv2MHz+4P2/LRskhfvSIlFt48aN9O3bl6lTpzJmzBhWrFhB586dnS5LRA6jqpb+l8BFwDII3rsfuj//TeDhQxw/EzjdGHN6jVZZhQp/cCJfrFdj+iLh5PF42LZtGy+//DIzZswgOVn7X4jUZVWN6c+z1i4lOHHPEBzTh2CL/tfGmFMhuDZ/6Pg9BBf0ubjWKj6EikCwpR/r1VKeIrWtpKSERx99lEAgQPPmzfnmm28YPny402WJSDVUt2lsCc7SDwBYa3OBnsCPwCJCXfwhs4AFNVhjlXI37gMgxqOWvkht+uqrr+jevTt//OMf+eCDDwCIjY11tigRqbZqpaS1ttxae5O1Nv+A53KstaXW2nOstaUHPP9/1tpPa6PYw2ndMNilWHnrnojULGst06dPp1u3buzYsYO5c+fSv39/p8sSkaPkiqZx5Zh+ZoqW4RWpDTfddBPjx4+nd+/e5Obmct555zldkogcgyrXxDTGxABNrbUbq3HsScD91trLaqK46qoM/TgtziNSKy677DKaNm3KrbfeikfDaCIRqzoLYXcCPgb23w9njGkCvA2ceWDXPpBCcNvdsCr3ayKfSE3y+/088MAD5Ofnc//999O7d2969+7tdFkicpyq85G9FDh4ad0KIAs4eDWc8kMcW+tKyyuX4dWKfCLHa8uWLQwaNIi77rqLH3/8kUAg7HtoiUgtqU7o+0N/DuSD4Pa7Bz3vyL8OZb5Q6Meq21HkeLz99ttkZWWxePFinnnmGV5++WV154u4iCv2uSz3hcb0tTiPyDHbsWMHl156KW3btmX27NmcdtppTpckIjXMFaG/JS84rUC77Ikcve3bt9O4cWMaNWrE3Llz6d69OwkJuhNGxI2qm5Jpxpi1lX+AXMAc+Fzo+fm1V+rhJYS69bUMr8jReemllzj55JOZNWsWAGeffbYCX8TFqtvSLwX+Uo3jmgG3Hns5x8aEFgTULXsi1VNQUMANN9zACy+8wFlnnUWfPn2cLklEwqC6oV9mrZ1Z1UGhtfjDHvr+0Nr7Xo9u2ROpysqVKxk2bBg//PADkydP5q677iImxhUjfSJSBVf8l+4LaJc9ker64YcfKCkp4f333+fss892uhwRCaOjDn1jzDjgLH55Gx9A2nFXdAxCDX3U0Bc5tJ07d7JkyRJ+9atfcdlll3HBBRdoG1yRKFSd0Df8fMJfElCf0L36B0mpiaKORijvifEYjFHqixzs/fffZ8SIERQVFfHjjz+Snp6uwBeJUtUJ/YTQHwCstY8Cjx7qQGPMaUBYd9iztvLa4byqSN3n8/mYPHky9913H6eccgpvv/026enpTpclIg6qMvSttZ9zQOhXIQ5IPK6KjpINpX6F31ZxpEj0qKiooH///nz88cdceeWVPProo2rdi0iNT+RbBbSp4XMeUWXUZyTFhvOyInVabGwsgwcP5vrrr2f48OFOlyMidUR1tta9GigkOHEv2Vr7nDGmA3AykGOt3XzA4Q2BXGPMqdbaPbVS8UEqu/djNHNfolxJSQm33HILQ4YMoV+/ftx1111OlyQidUx1WvpPAh8RnNDXG3gOyAamAeXGmCLgCWAG8DQwJ1yBD2BDbf1YTd2XKPbVV18xbNgwvvzyS1q2bEm/fv2cLklE6qDqNI8LrbX9rbXnAEUHPL/IWtsUGAi0BbYRXJHvjzVf5uGppS/RzFrL9OnT6datGzt27GDu3LncfvvtTpclInXUEZPSGBMLHNiE9hpj4kLPpRhjfg3cBlwE/BNoDoR1enDlRL5Ne4vDeVmROuE///kP48ePp0+fPuTm5nLeeec5XZKI1GFVNY89wKwDvl8aei4e6AkMB1YAna2144DpwP/WQp1VapoW1psGRBxVUFAAwK9+9Stmz57N3LlzadKkicNViUhdd8TQt9aWAeuMMX80xvwRmG+tLQVeA/paa4dba5/hp0V5/gb81hiTWatVH1hj6Gu6Zu9LFPD7/dx7772cdNJJbNiwAY/Hw9ChQ/F4NLwlIlWrzr8U9wNZQGfgvtBz+UCOMSbOGJNA8IOB11pbCAy21u6snXJ/af+Yvibyictt2bKFgQMHMmHCBM4991zS0hxZ9VpEIli17tO31l4JYIy5IvR9mTHGWGvLQ88ba60/9Nri2ir2MNUB2mFP3O2tt95izJgxFBcXM2PGDMaMGaNlp0XkqFUr9I0xZxHqFajisQGw1n5YG8Ueyk8tfXVvinvNnj2bZs2a8corr9CuXTunyxGRCGUqZ78f9gBjFgNl/DR8fiSxQJy1tnsN1FYt7Tp2tqUX3kvPNvWZfU2vcF1WpNatWbOGQCDAqaeeSmFhITExMSQkVHdFbBFxM2PMCmtt9tG+74gtfWNML+BD4BFr7dZjLa42+UP76haVHWqnX5HI9OKLL3L99deTnZ3N+++/T0pK2DewFBEXqqp7vxEwAPijMWYFwRb/kXiABGttz8MdYIx5FmgPvGWtnXqE4xoDc621ZxzxgqFhzQp/oIrSROq+goICfv/73/Piiy9y9tln88ILLzhdkoi4yBFD31r7BvCGMeZE4ArgKoK35z0BrDzEW7wcYUc+Y8zvAK+1tpcxZoYxpq21ds1hDn+YauzYVzk60aJ+UlWHitRp69atY9CgQaxdu5bJkyczYcIEvF6v02WJiItUd/b+BuAeY8x9wJXAX4FJ1tonj/J6/YA5ocfzgD7AL0LfGNOf4JK/26qsLfQ11quZzBLZmjVrxmmnncazzz7L2Wef7XQ5IuJCRzXl3Vrrt9b+AzgD+PsxXC8ZqNyVbw/Q+OADQsv8TgT+fLiTGGOuMcbkGGNy8vPzAfBq9r5EoJ07dzJ+/Hjy8vKIj4/nP//5jwJfRGrNMSWltXZj5X35R6mQn7rsUw5z/T8DT1pr9x3h+tOttdnW2uyklFRAu+xJ5Fm4cCFZWVk8//zzLFmyxOlyRCQKhLt5vIJglz4EV/lbf4hjzgV+b4z5AOhsjHnmSCcMhGbv55dW1FiRIrXJ5/Nx1113ce6551KvXj2WLVumjXJEJCyqNaZfg14HPjLGNAPOB4YZY6ZaaydUHmCt3d+3aYz5ILSRz2F5THBcPz5WE54kMtx222387W9/48orr+TRRx8lOTnZ6ZJEJEqENfSttfnGmH7AQOBBa+02IPcIx/er8pyhr03qadESqdvKy8uJi4vjlltuoUePHgwdOtTpkkQkyoR99pu1dq+1dk4o8I9bqHefWK8m8kndVFxczPjx47nooosIBAI0b95cgS8ijoj4pCz3aVEeqbu+/PJLunfvzvTp0+nSpQuBgP6+iohzwj2mX+Mq78/PKyl3uBKRn1hr+fvf/85NN91EWloa8+bNY+DAgU6XJSJRLuJb+pUr8p2QoRX5pO4oLCzkvvvuo2/fvuTm5irwRaROiPiWfuVEvhjdpy91wIoVK+jYsSOpqal88sknNG/eHI8WjhKROsI1/xp5FfriIL/fz7333kuPHj146KGHAGjRooUCX0TqlMhv6Yf69xX64pQtW7YwcuRI3n//fYYPH86NN97odEkiIocU+aEf+qrufXHCwoULGTp0KMXFxcyYMYMxY8ZgjP4uikjdFPGhHwi19D0KfXFAZmYmJ598Ms899xzt2rVzuhwRkSOK+AHHCl8w9P2Vq/SI1LLvvvuOv/71rwB07NiRTz/9VIEvIhEh4kO/8j59q8yXMHjhhRfo0qULDz/8MFu2bAFQd76IRIyID/3KrG+QEudoHeJuBQUFjBo1iiuuuIKuXbuSm5tLs2bNnC5LROSoRPyYfmULP0a3RkktsdbSv39/Vq5cyeTJk5kwYQJer3Z1FJHI44LQD6Z+ZTe/SE0JBAIYYzDGMHHiRNLT0zn77LOrfqOISB0V8c3jkgo/oPv0pWbt2LGDiy66iMcffxyAX//61wp8EYl4ER/68THBbtYy7bYnNWTBggVkZWWxcOFC4uI0V0RE3CPiQ79SWmKs0yVIhKuoqODOO+9k4MCBZGRksGzZMsaPH+90WSIiNSbiQ9+iZXilZuTk5HD//fdz1VVXsXz5cjp16uR0SSIiNSriJ/JVUubLsVq9ejWnnXYavXr1Ijc3l44dOzpdkohIrYj8ln7olj2PFkiRo1RcXMz48eM5/fTTWbp0KYACX0RczUUtfYW+VN+XX37JsGHD+Oqrr7j99tvp0qWL0yWJiNS6iA/9yhX5NKYv1fXMM89w4403kpaWxrx58xg4cKDTJYmIhEXEd++j7n05Snl5efTt25fc3FwFvohElYgP/crZ+1qFV47kk08+Ye7cuQDcdNNNvP322zRu3NjhqkREwss1UelVS18Owe/3M3XqVPr27cvEiROx1uLxePDoU6KIRCHX/Mun7U3lYJs3b+bcc89l4sSJDBkyhAULFujviYhEtYifyBcIjenHx7jm84vUgM2bN5OVlUVJSQnPPfccV1xxhQJfRKJexId+5US+GO2yJwR3XTTG0KxZM2644QaGDRtGu3btnC5LRKROiPjmsZbhlUrfffcdZ599NqtXr8YYw+TJkxX4IiIHcEHoB8VqYlbUstYyc+ZMunTpwtdff82WLVucLklEpE6K+KSsXIbXq+79qFRQUMCoUaMYM2YM2dnZfPHFFwwYMMDpskRE6qSID/1AKPVj1L0flf72t78xa9YspkyZwoIFC2jevLnTJYmI1FmRP5EvJEbd+1EjEAiwbds2mjVrxu23387gwYPp3r2702WJiNR5rklKtfSjw44dO7jooovo3bs3hYWFxMfHK/BFRKrJNS19j0Lf9RYsWMDIkSPZu3cv06ZNIzk52emSREQiiita+rpdz918Ph933nknAwcOJCMjg2XLlnH99ddrsR0RkaPkjtDXP/6uZozh008/Zdy4cSxfvpxOnTo5XZKISERyRfe+Mt+dXnvtNc4880yaNGnC3LlzSUhIcLokEZGI5o6Wvrr3XaW4uJhrrrmGSy65hIceeghAgS8iUgNc0dJX9757rFq1imHDhrF69Wr+/Oc/M2XKFKdLEhFxDVeEvmbuu8PcuXO5+OKLSUtL491332XgwIFOlyQi4iqu6N5X5rtD9+7dGTZsGLm5uQp8EZFa4IrQ31tc4XQJcow+/vhjLr30UsrLy6lfvz7PPfccjRs3drosERFXckXoN6mnSV6Rxu/3c88999C3b18+//xzNm/e7HRJIiKu54rQV/d+ZNm8eTPnnnsukyZNYtiwYaxcuZLWrVs7XZaIiOu5YiKfVmaLLMOHD2flypU8//zzjB49Wv//iYiEiStCXxvs1X1lZWX4/X6SkpJ4+umn8Xq9nHrqqU6XJSISVVwRlx61FOu0b7/9lp49e3LjjTcC0L59ewW+iIgDFPpSa6y1PP/883Tt2pWNGzdy8cUXO12SiEhUc0XoK/Prnvz8fEaOHMnYsWPp1q0bubm5XHTRRU6XJSIS1VwR+mrp1z27d+9m7ty53HPPPcyfP5/mzZs7XZKISNRzx0Q+ZX6dEAgEeP3117n44otp3bo1P/zwA+np6U6XJSIiIWrpS43YsWMHF154IZdccglvvfUWgAJfRKSOcUVLX/d5O2v+/PmMGjWKvXv38uSTT3LhhRc6XZKIiByCS1r6TlcQvR588EEGDRpERkYGy5cv57rrrtOHMBGROsoVof/NtgKnS4haZ5xxBuPGjSMnJ4eOHTs6XY6IiByBK7r3s05Ic7qEqDJnzhx+/PFHbr31VgYOHKhtcEVEIoQrWvpe9e+HRVFREVdffTVDhw7ljTfewOfzOV2SiIgchbCHvjHmWWPMYmPMhMO8nmaMeccYM88Y829jTFxV59Ts/dr3xRdfkJ2dzbPPPssdd9zB+++/T0yMKzqKRESiRlhD3xjzO8Brre0FtDHGtD3EYSOAadbaQcA2YHBV51VLv3bt3buXPn36sG/fPt577z3uu+8+YmNjnS5LRESOUribav2AOaHH84A+wJoDD7DWPnnAt5nAjoNPYoy5BrgGIK7JyQr9WlJSUkJiYiIZGRnMnDmT3r1706hRI6fLEhGRYxTu7v1kYHPo8R6g8eEONMb0AjKstUsOfs1aO91am22tzQa19GvDxx9/zKmnnsobb7wBwMUXX6zAFxGJcOEO/UIgMfQ45XDXN8bUBx4DrqzOSb0a068xfr+fKVOm0LdvX+Li4rRmvoiIi4Q79FcQ7NIHyALWH3xAaOLeq8Ad1tofq3NSW1PVRblNmzYxYMAA7r77boYPH87KlSvJzs52uiwREakh4Q7914FRxphpwBDgK2PM1IOOuQroAtxljPnAGDO0qpNu3FNc85VGoYULF5KTk8PMmTN56aWXqFevntMliYhIDTLWhredbIzJAAYCH1prtx3v+eKbtrXj/vcVnri8y/EXF4XKyspYuXIlvXr1wlrL1q1badasmdNliYjIERhjVlTOazsaYb9P31q711o7pyYCv5Lu0z823377LT179mTgwIHs3LkTY4wCX0TExVyxIp8m7x8day3PP/88Xbt2ZePGjcyePZvMzEynyxIRkVrmitDX7P3q8/v9jBo1irFjx9KtWzdyc3O56KKLnC5LRETCwBWhr61cq8/r9dKoUSPuuece5s+fr1vyRESiiCsWT1f3/pEFAgGmTZvGWWedRY8ePZg2bZrTJYmIiANc0dLXRL7D2759OxdccAG33nors2bNcrocERFxkDta+q746FLz5s2bx+jRo8nLy+Opp55i/PjxTpckIiIOckXoa0z/lxYsWMB5551H+/btmT9/PqeffrrTJYmIiMNc0UbWmP5P/H4/AP369ePhhx9m+fLlCnwREQFcEvq6ZS/olVdeoX379mzbtg2v18stt9xCUlKS02WJiEgd4YrQ90R5U7+oqIhx48YxbNgw6tevT0VFhdMliYhIHeSK0I/mlv4XX3xBdnY2M2bM4M477+TDDz+kRYsWTpclIiJ1kEsm8jldgXPuu+8+8vLyeO+99xgwYIDT5YiISB3mktCPrtTfs2cPRUVFtGjRgieffBK/36+180VEpEqu6N6Ppsj/6KOP6Ny5M5dffjnWWurXr6/AFxGRanFF6EdD6vv9fqZMmUK/fv2Ij4/nkUceiboeDhEROT7u6N53eerv2LGDIUOGsGjRIkaOHMmTTz5Jamqq02WJiEiEcUfouzvzSU5Opri4mJkzZzJ69GinyxERkQjliu59N2Z+aWkpU6dOpaioiOTkZJYsWaLAFxGR4+KO0HdZ6n/zzTf07NmTiRMn8uabbwLg0a5CIiJynFyRJG4Z07fWMmPGDLp27crmzZt58803GTp0qNNliYiIS7gj9N2R+UydOpWrrrqKHj16kJuby4UXXuh0SSIi4iLumMjndAHHyVqLMYYRI0YQFxfH//zP/+D1ep0uS0REXMYlLf3IjP1AIMBDDz3EkCFDsNbSpk0bbr/9dgW+iIjUCpeEvtMVHL3t27dzwQUXcNtttxEIBCgtLXW6JBERcTl3hH6EdfDPmzePrKwsFi1axNNPP82//vUvEhMTnS5LRERczh1j+hGU+cXFxYwZM4YGDRowf/58Tj/9dKdLEhGRKOGO0He6gGrYuHEjzZo1IykpiXfffZeTTjqJpKQkp8sSEZEo4o7u/Tqe+q+88gqnn346DzzwAAAdO3ZU4IuISNi5JPTrZuoXFRUxbtw4hg0bRocOHbj88sudLklERKKYK0K/Llq1ahXZ2dnMmDGDO++8k0WLFtGqVSunyxIRkSjmjjH9OtjQLykpobi4mPnz59O/f3+nyxEREXFHS7+u3LK3e/duZsyYAUD37t1Zs2aNAl9EROoMd4R+Hcj8Dz/8kM6dO3Pdddexfv16AOLi4pwtSkRE5ADuCH0Hr+3z+Zg8eTLnnHMOiYmJLF68WGP3IiJSJ2lM/zhYa/n1r3/NO++8w6hRo3jiiSdITU11phgREZEquCL0PQ6lvjGGyy+/nOHDhzNq1ChHahAREakuV4R+jCd8oV9aWsqtt95Kly5dGDt2LCNHjgzbtUVERI6HO8b0w9TSX716NT169ODxxx/n+++/D8s1RUREaoorWvq1nfnWWp577jluvPFGkpKSeOutt7jgggtq96IiIiI1TC39asjJyeGqq66iR48e5ObmKvBFRCQiuaOlX0vn3blzJ5mZmXTr1o25c+dy7rnn4vV6a+lqIiIitcslLf2aPV8gEODBBx+kVatWLF++HIDzzjtPgS8iIhHNJS39mkv97du3M3r0aObNm8cll1zCySefXGPnFhERcZJa+geYN28eWVlZfPjhhzz99NO8+uqrZGRk1MzJRUREHOaSln7NWLx4MQ0bNmTBggV06NChhs4qIiJSN0R9S3/t2rV88sknAEyYMIHly5cr8EVExJVcEvrHlvqzZs2ic+fOjBs3Dr/fj9frJTExsYarExERqRvcEfpHeXxRURFXXnkll19+OR07dmTu3LmamS8iIq7njjH9o2jp79y5k7POOovvvvuOCRMmcPfddxMT44pfg4iIyBG5Iu2OpqXfsGFDzjnnHJ566inOOeecWqtJRESkrnFH934Vqb97925GjBjB2rVrMcYo8EVEJCq5PvQXLVpEVlYWr7766v7V9URERKKRK0Lfc4jU9/l8TJ48mf79+5OUlMSSJUsYOnSoA9WJiIjUDa4IXEfHTQAACgRJREFU/UOZNm0af/nLXxg5ciQrVqygS5cuTpckIiLiKHdM5DugpV9YWEhKSgq///3vOemkk7jkkkscrExERKTucEVL3wClpaXccMMNdO/enaKiIpKTkxX4IiIiBwh76BtjnjXGLDbGTDieYw60ad0aevTowRNPPMHgwYN1372IiMghhDX0jTG/A7zW2l5AG2NM22M55kD+4nxuGn4+W7Zs4a233mLatGnEx8fXzg8gIiISwcLd0u8HzAk9ngf0OcZj9guU5NGuU1dyc3O54IILaqhMERER9wl3P3gysDn0eA9wqCn1VR5jjLkGuCb0bVnuso+/bN68eQ2XKgdpCOxyugiX0++49ul3XPv0Ow6PU4/lTeEO/UKgchu7FA7d01DlMdba6cB0AGNMjrU2u+ZLlQPp91z79Duuffod1z79jsPDGJNzLO8Ld/f+Cn7qrs8C1h/jMSIiInKUwt3Sfx34yBjTDDgfGGaMmWqtnXCEY3qGuUYRERFXCmtL31qbT3Ci3hLgHGtt7kGBf6hj8qo47fRaKFV+Sb/n2qffce3T77j26XccHsf0ezbW2pouREREROogV6zIJyIiIlWLmNCvjZX85P+3d/fBVlVlHMe/Py4X0CIgTXAalRoaXylgCt96uagE6pg42jiEBTqN4RiKOlPCjGnNlL0Nk4k0Ymk1mVmWGBOoUJL0goUVRdKYUzom2ttEiiCEPP2x1oHN6d579oF7j519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\n",
      "text/plain": [
       "<Figure size 576x432 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.rcParams[\"font.sans-serif\"] = [\"SimHei\"]\n",
    "def plot_roc_curve(fpr, tpr,label = None):\n",
    "    plt.plot(fpr, tpr, linewidth = 2, label = label)\n",
    "    plt.plot([0,1],[0,1],\"k--\")\n",
    "    plt.axis([0,1,0,1])\n",
    "    plt.xlabel(\"假正类率\", fontsize = 16)\n",
    "    plt.ylabel(\"假正类率\", fontsize = 16)\n",
    "\n",
    "plt.figure(figsize=(8,6))\n",
    "plot_roc_curve(fpr,tpr)\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.9613704281575988"
      ]
     },
     "execution_count": 73,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 计算曲线下面积AUC，虚线是随机分类0.5到1\n",
    "\n",
    "from sklearn.metrics import roc_auc_score\n",
    "\n",
    "roc_auc_score(y_train_5, y_scores)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 召回率TPR越高，分类器的假正类FPR就越多\n",
    "# 虚线表示随机分类器的ROC曲线，好的分类器应该远离这条线，向左上角\n",
    "# 是使用精度/召回率PR曲线，还是使用ROC，关键在于非正类非常少或者更关注假正类而不是假负类，选择PR，反之ROC\n",
    "#  例如：前面的例子ROC曲线很不错是因为跟负类 非5相比，正类 数据5 数量是真的很少"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 训练随机森林分类器，比较SGD分类器的ROC曲线和ROC  AUC分数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 获取训练集中每一个实例的分数\n",
    "## RandomForestClassifier没有decision_function,但是拥有dict_proda方法，sklearn中分类器都有这两个中的一个\n",
    "## dict_proda返回一个矩阵，每行一个实例，每列代表一个类别的概率，比如这个图片70%是5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.ensemble import RandomForestClassifier\n",
    "forest_clf = RandomForestClassifier(n_estimators = 10,random_state = 42)\n",
    "y_probas_forest = cross_val_predict(forest_clf,X_train,y_train_5,cv=3,\n",
    "                                    method = \"predict_proba\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1. , 0. ],\n",
       "       [1. , 0. ],\n",
       "       [1. , 0. ],\n",
       "       ...,\n",
       "       [1. , 0. ],\n",
       "       [1. , 0. ],\n",
       "       [0.8, 0.2]])"
      ]
     },
     "execution_count": 75,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_probas_forest"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 绘制ROC曲线，需要分数值而不是概率，直接使用正类发概率作为分数值\n",
    "\n",
    "y_scores_forest = y_probas_forest[:,1]\n",
    "fpr_forest ,tpr_forest,threshold_forest = roc_curve(y_train_5,y_scores_forest)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0. , 0. , 0. , ..., 0. , 0. , 0.2])"
      ]
     },
     "execution_count": 77,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_scores_forest"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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jlWypOuWDg93Xxn16AF//AEbNkCXLm5b9+6uxVu7tnteujScd577t+jePf21Z54Jr78OVTJ0EJcu7VrW1avzT7d1SAg8+ig884zLnebuu93/D2n/ZgDnn++6uTMqX9797pk9/fTx26pUgf/979htZ5zhvjIKDYWzzjr+9X6yceNGBgwYwLhx47jyyivp169fvhzXk6Jvre2S+n0psDTTzzYbY3rgWvv3W2uTA5/weNZaYuMTjyvaWRX1vw8lkJzbSg5ULBVyXNHOqqhXKhVKiWAtrSCFT3y8K1BlyqS3jLdsgehoaNIEGjaElBSYPdu1VBs1giuvdPvt2wf//rd73QcfpB/TGPfmfuSIe7xvnyume/fCiBGu5Veliit4CxYc2/26eTMsXOgKfMaMGzak50sTl3oBceXK9MLZqZNrcR85kr5f9equGz1jyzIiwrXQmzZN31a6tPtwkrlAP/WUO1da4SxRAp57zrX8K1dO3+/yy6FXL9d1nZa1Vq3jiym43zGz//73+G2dOrmvjKpUgeHDj983rbs7o6yGTZUs6b4kf1lreeWVV7j99tupUKECldK6cPKJyTyQqqjJz2v6P+88yIrf9mQo4ulFfU/cURKTc/9vVT48JMsWeJWyrss97XnlMqGEqJBLAdm1y7Uia9RIf4PetMkV5DPOgDp13LatW11XcocO0KeP27ZvH9xzjxvA9MQT6cds29a1GB95xBXj9evhppvg669da7dzZ7ff3Xe74vf883DLLa5F+8QTrju8Xr30Ft2uXa6QnnkmfPghnH222161quuujYlx3b7guqd/+QVmzXItSHCt+uRkV7AjIty2P/5w3b916qQXrMOH4ddf3TXYBg3Sf5//+z/3gaR+/fSBYgkJrigH6T9NCaC9e/dy7bXX8u6779KrVy9mzJhBRNofdSbGmLXW2jzPbiuM1/QD7nBCEs8u+oWpyzedsKu9bFiJHLvVq5R1hTysRHDgfgEpcrZvd0WoVq30FuGGDa4gdu+e3nW5eTPMm+daglenLlX1119w223u+uHEiW5bSoor6ikpbiBTmssugxUr3HHPPddtmzLFddc+8giMGeO2xcS4bT16pBf9+Hh49VXXws1Y9H//HaZNc0V+2TKIjHRFN7P69V23clo3c61a8Nhjrpu4fv30/cqX559BY2kfQsD1ElSuzDEjqZ966vjzXH758duy6hIuVcplzSpnZqGhx28TKWiLFy/mgw8+4KmnnuK2224jqAA+dRb7ov/lL39x7/sb2bo3niADl7aoQd3TynBa2dBjWuRVyoZRMkSFvDg6etS1HMuUgZo13bbNm9015K5d3XVicNdiO3RwrdKMg4euucYVytdfd4OFAK64wo1aXrHCjaYGd7x33nFd2Hfc4bZ99x3ceacbdHTJJa5L+8gReOMNV0TTin5QUPq14JSU9BZqjRqu+AVn+NOtV8919aYVY3D7DB2aPhgM3KCpSZPSr6mnWbnStfBr1Uo/z4oVxw7SAtcFP2LEsdtKlXLXxDMqWRKGDOE4GfOJ+FVycjIxMTG0atWKfv36ERUVRb169QruhNbaIv3VunVrezL+jjtqb33rW1vnro9snbs+sr2e+9Ku37LvpI4lRdMXX1j76KPWbtyYvu3FF62tWtXaV19N33bXXdaCtbfemr5t8WK3rX379G1Hj7ptQUHWJiamb2/a1G3fsCF925VXWlu/vrVr1qRvmz7d2nPPtXbKlPRtGzdae8MN1j7xhLXbtrlthw5ZO3Omte+9d+zvc+SIO29KSt7/LUQk8LZt22a7dOliS5YsaTdv3pyn1wLR9iRqZrFr6Vtree/b7Tz00Q/sO5xIWIkgbu1+FiM61tW19SJo92439encc9NHG0+f7lrCr7zirhODa10+8YQbSJY2CPbuu9NbrWkDseLj3TXm99+H665z26Ki3HXtnTvTz3vGGW7kcsZWcIkS8MIL7nglMvyX9dprris/40ybefM4ztCh7iujpk3dnOWMSpXKerBVxlHUIlK4ffTRRwwbNoz4+HgmTZpE7QB1bRWror9172HGvLeRr37dA0CHMyszoW8zzjgtn1dSkFO2eLEbTHXhhe75tm1w771uCtUvv7jCt2mT66oG1/2edj142jT48ktYtSq96Fvrur/nzUsv+rff7gaYZbz226+fG22eNnAMXFf8FVccm+/MM4+fchQUdOwI8jTt2p3Mv4CI+JG1lttvv53nnnuOFi1a8NZbb9GwYcOAnb9YFP2k5BRe/3oTzyz6hSOJKZQPD2HsRWdzRetaWsgkgI4ccYuGlCsHPXu6bda6gnrwYPr0o9hYN6AM3KC04GA3fembb9wAuG++cdfS69Z1K2J9+qm79p1W9P/zH/f6jJfFrrrKjQpPG1kOWRfz0093XyIiBcEYQ3BwMLfccguPP/44JQM879H3U/a+2x7L3e9u4Lvt7h4/l0TW4P6LG3NaGfWFFrTPP4dvv3UjzQHWrnVd5bVruyljaUJD3ejvo0fTu8W7dXMLn2zblj6Sevp015q+6KJj5zWLiBRm1lpmzpxJgwYN6NChA9baU25waspeJglJKTy18GemLt9EcoqlZoVwHu7blPMbZj3nUU7enj0wYYJrhU+c6OZK79zpVucCt6xmyZKupd269fHXntPmXGecnbJkyfHnGTaswH4FEZECcfDgQW644QbeeOMNBg8eTIcOHTztYfbtyLWXlv0fk7/8HWstV59bl4W3dVLBP0lJSccuEzpihJuuFRPjnleu7AbEzZvnFnQBt9hK377u8fbUeyaWKuXmXn/99bHH79/frUCmhVBExE+io6Np2bIlb775Jg899BDTpk3zOpI/i/6ho0lMX/EHAFOHtuH+ixtTOsy3nRr55ptv3EjxtWvTtw0c6JYC/egjN/8b3PKd27e7Ee7gRquPGOHmoWdcovTdd901+7TBdCIixcXq1avp0KEDCQkJfPHFF4wdO5bgYO/XevFl0X9z9RZi4xNpXaci5zdS6z6ztMFztWq5FdfATX177TU3CG7+/PT9zku9c9hdd6UvvtKtm1vJ7e670495zTVuHe+0pVFFRIqjlNTWUevWrRk7dizr16/nvLQ30kLAd0U/ISmF177aBMANndXEBDdHvHbt9FXeEhPd6Pnt292dvMBdh0+bypa2VKkxMGCAG0z3xx/pRT9t3XXNCxcRSbd48WJatGjBjh07CA4O5v7778/3G+acKt8V/fnrt7PzwBEaRJShazFs5e/a5Raq6d07fVtCgivc06a5a++hoW5N9vnz4cUMNzXu2dO17jOuZV65cvrSsyIicrzExETuueceevbsSVJSEgcOHPA6UrZ8daE7JcXyyhe/AXB95zMJ8vn95JOS3LrtSUmugJ9+urtf965dbi303btdC75sWRg1yg2Ua9PGvfa009xa7iIicvI2bdrEwIEDWbVqFddeey3PPfccpTLeJaqQ8VXRX/zjLn776xA1ypfkkhY1vI6T76Kj3TKvU6a4rvWDB11L/LPP3Lz300930+SWLXOt+rS57MHBWd+dTERETs348eP56aefmDt3Lv3SrpEWYr7p3rfW8vLnrpU/omM936yj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\n",
      "text/plain": [
       "<Figure size 576x432 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(8,6))\n",
    "plt.plot(fpr,tpr,\"b:\",linewidth = 2,label = \"SGD\")\n",
    "plot_roc_curve(fpr_forest,tpr_forest,\"Random_Forest\")\n",
    "plt.legend(loc = \"lower right\",fontsize=16)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.9929487459168216"
      ]
     },
     "execution_count": 80,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# RandomForest 比SGD 好很多，ROC  AUC 的分数也高很多\n",
    "roc_auc_score(y_train_5,y_scores_forest)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.9839277851166887"
      ]
     },
     "execution_count": 81,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 再看一下精度和召回率也很高\n",
    "\n",
    "y_train_pred_forest = cross_val_predict(forest_clf, X_train,y_train_5,cv=3)\n",
    "precision_score(y_train_5,y_train_pred_forest)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.8243866445305295"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "recall_score(y_train_5,y_train_pred_forest)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 多类别分类器\n",
    "# 1.尝试5之外的检测\n",
    "# 2. 多类别分类器区分两个以上的类别\n",
    "# 3. 随机森林和朴素贝叶斯可以直接处理多个类别\n",
    "# 4. 支持向量机SVM和线性分类器只可以处理二元分类器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 解决方案\n",
    "## 1. 将数字图片分类0到9，训练10个二元分类器，每个数字一个，检测一张图片时，获取每个分类器的决策分数，哪个最高属于哪个，称为一对多OvA\n",
    "## 2. 为每一对数字训练一个二元分类器，区分0，1；区分0，2和区分1，2称为一对一OvO策略，存在N个类别，需要N*(N-1)/2 个分类器，最后看哪个类别获胜最多\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 优缺点\n",
    "## 1. OvO只需要用到部分训练集对其必须区分两个类别进行训练\n",
    "## 2. 对于较小训练集合OvO比较有优势，大训练集合OvA速度快，所有OvA更常用，比如svm在数据规模扩大时表现糟糕\n",
    "## 3. skleanr检查使用二元分类算法进行多类别分类任务，会自动运行OvA，svm分类器除外\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array(['9'], dtype='<U1')"
      ]
     },
     "execution_count": 84,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sgd_clf.fit(X_train,y_train)\n",
    "sgd_clf.predict([some_digit])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-42061.80824386, -17482.09027701, -19886.83524155,\n",
       "         -7263.20750296,  -4800.98287798,  -5315.73273023,\n",
       "        -26480.85107453, -11288.93162602,  -6335.75091817,\n",
       "         -3659.38110801]])"
      ]
     },
     "execution_count": 85,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 内部实际上训练了10个二元分类器，获得图片的决策分数，然后选择了分数最高的类别\n",
    "# 返回10个分数，每个类别1个\n",
    "some_digit_scores = sgd_clf.decision_function([some_digit])\n",
    "some_digit_scores"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "9"
      ]
     },
     "execution_count": 86,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.argmax(some_digit_scores)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], dtype='<U1')"
      ]
     },
     "execution_count": 87,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 目标类别列表会存储在classes_这个属性中，按值大小排列\n",
    "sgd_clf.classes_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array(['4'], dtype=object)"
      ]
     },
     "execution_count": 88,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 使用OvO策略，一对一或者一对多\n",
    "\n",
    "from sklearn.multiclass import OneVsOneClassifier\n",
    "ovo_clf = OneVsOneClassifier(SGDClassifier(max_iter = 5, tol =-np.infty,random_state =42))\n",
    "ovo_clf.fit(X_train,y_train)\n",
    "ovo_clf.predict([some_digit])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "45"
      ]
     },
     "execution_count": 89,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(ovo_clf.estimators_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array(['9'], dtype=object)"
      ]
     },
     "execution_count": 90,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 使用随机森林\n",
    "\n",
    "forest_clf.fit(X_train,y_train)\n",
    "forest_clf.predict([some_digit])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 1.]])"
      ]
     },
     "execution_count": 91,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 随机森林直接将实例分为多个类别，调用predict_proba()可以获得分类器将每个实例分类为每个类别的概率列表\n",
    "forest_clf.predict_proba([some_digit])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 评估分类器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.87525, 0.8741 , 0.86755])"
      ]
     },
     "execution_count": 92,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 使用交叉验证评估SGD的准确度\n",
    "cross_val_score(sgd_clf , X_train, y_train,cv=3,scoring = \"accuracy\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.89275, 0.8977 , 0.89765])"
      ]
     },
     "execution_count": 93,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 将输入进行简单缩放，可以得到准确率90%以上\n",
    "\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "\n",
    "scaler = StandardScaler()\n",
    "\n",
    "X_train_scaled = scaler.fit_transform(X_train.astype(np.float64))\n",
    "\n",
    "cross_val_score(sgd_clf,X_train_scaled,y_train,cv=3,scoring = \"accuracy\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 错误分析\n",
    "# 1. 项目流程 \n",
    "# 1.1 探索数据\n",
    "# 1.2 尝试多个模型\n",
    "# 1.3 选择最佳模型并用GridSearchCV对参数进行微调\n",
    "# 1.4 尽可能自动化\n",
    "\n",
    "# 2. 确定一个相对合适的模型，进一步优化，分析其错误类型\n",
    "# 2.1 查看混淆矩阵\n",
    "# 2.2 使用cross_val_predict()进行预测\n",
    "# 2.3 调用confusion_matrix()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_train_pred = cross_val_predict(sgd_clf,X_train_scaled, y_train,cv=3)\n",
    "conf_mx = confusion_matrix(y_train,y_train_pred)\n",
    "conf_mx"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 使用matplotlib的matshow函数来查看混淆矩阵的图像表示\n",
    "\n",
    "plt.matshow(conf_mx,cmap = plt.cm.gray)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 看起来不错，大多数图片都在主对角线上，说明他们被真缺分类\n",
    "# 数字5看起来比较暗，说明要么数字5图片较少要么分类器在数字5上执行效果不如其他数字好\n",
    "#  假设把角度放在错误上，为取得错误率，而不是错误绝对值，需要将混淆矩阵中每个值除以相应类别中的图片数量\n",
    "\n",
    "row_sums = conf_mx.sum(axis = 1 ,keepdims =True)\n",
    "norm_conf_mx = conf_mx / row_sums"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 用0填充对角线，只保留错误，重新绘制\n",
    "\n",
    "np.fill_diagonal(norm_conf_mx,0)\n",
    "plt.matshow(norm_conf_mx,cmap = plt.cm.gray)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 每行代表实际类别，每列代表预测类别\n",
    "# 9 ， 9 列比较亮，说明许多图片被错误的分类为数字8 ，9\n",
    "# 类别8 ，9 行也偏高，说明数字8和9经常会和其他数字混淆\n",
    "# 有些很暗，比如行1，大多数数字1都能被正确分类，一些和8混淆\n",
    "# 5和3是错误最多的\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 结论\n",
    "\n",
    "# 1. 改进数字8和9的分类\n",
    "# 2. 修正数字3和5的混淆"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 如何优化分类器\n",
    "\n",
    "#1. 尝试多收集这些数字的训练集\n",
    "#2. 开发一些新特征来改进分类器\n",
    "#3. 优化分类器算法\n",
    "#4. 使用pillow或者opencv对图片预处理，让显示模型更突出\n",
    "#5. 分析单个错误\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "unhashable type: 'numpy.ndarray'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-78-2c5b8d6075da>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     21\u001b[0m \u001b[0mX_ba\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mX_train\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0my_train\u001b[0m \u001b[1;33m==\u001b[0m \u001b[0mstr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc1_b\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m&\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0my_train_pred\u001b[0m \u001b[1;33m==\u001b[0m \u001b[0mstr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc1_a\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m)\u001b[0m \u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     22\u001b[0m \u001b[0mX_bb\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mX_train\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0my_train\u001b[0m \u001b[1;33m==\u001b[0m \u001b[0mstr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc1_b\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m&\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0my_train_pred\u001b[0m \u001b[1;33m==\u001b[0m \u001b[0mstr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc1_b\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m)\u001b[0m \u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 23\u001b[1;33m \u001b[0mCounter\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mX_aa\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     24\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     25\u001b[0m \u001b[0mplt\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfigure\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfigsize\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m(\u001b[0m\u001b[1;36m8\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m8\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\Anaconda\\anaconda\\lib\\collections\\__init__.py\u001b[0m in \u001b[0;36m__init__\u001b[1;34m(*args, **kwds)\u001b[0m\n\u001b[0;32m    566\u001b[0m             \u001b[1;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'expected at most 1 arguments, got %d'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    567\u001b[0m         \u001b[0msuper\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mCounter\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__init__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 568\u001b[1;33m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    569\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    570\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m__missing__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkey\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\Anaconda\\anaconda\\lib\\collections\\__init__.py\u001b[0m in \u001b[0;36mupdate\u001b[1;34m(*args, **kwds)\u001b[0m\n\u001b[0;32m    653\u001b[0m                     \u001b[0msuper\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mCounter\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0miterable\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# fast path when counter is empty\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    654\u001b[0m             \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 655\u001b[1;33m                 \u001b[0m_count_elements\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0miterable\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    656\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mkwds\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    657\u001b[0m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mkwds\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mTypeError\u001b[0m: unhashable type: 'numpy.ndarray'"
     ]
    }
   ],
   "source": [
    "def plot_digits(instances, images_per_row = 10,**options):\n",
    "    size = 28\n",
    "    images_per_row = min(len(instances),images_per_row)\n",
    "    images = [instance.reshape(size,size) for instance in instances ]\n",
    "    n_rows = (len(instances)-1 ) // (images_per_row + 1)\n",
    "    row_images = []\n",
    "    n_empty = n_rows * images_per_row - len(instances)\n",
    "    images.append(np.zeros((size,size * n_empty)))\n",
    "    for row in range (n_rows):\n",
    "        rimages = images[row * images_per_row:(row + 1) * images_per_row]\n",
    "        row_images.append(np.concatenate(rimages,axis = 1))\n",
    "    image = np.concatenate(row_images ,axis = 0)\n",
    "    plt.imshow(image,cmap = matplolib.cm.binary, **options)\n",
    "    plt.axis(\"off\")\n",
    "    \n",
    "# 查看数字3和5 的例子\n",
    "from  collections import Counter\n",
    "c1_a, c1_b = 3, 5\n",
    "X_aa = X_train[(y_train == str(c1_a)) & (y_train_pred == str(c1_a) ) ]\n",
    "X_ab = X_train[(y_train == str(c1_a)) & (y_train_pred == str(c1_b) ) ]\n",
    "X_ba = X_train[(y_train == str(c1_b)) & (y_train_pred == str(c1_a) ) ]\n",
    "X_bb = X_train[(y_train == str(c1_b)) & (y_train_pred == str(c1_b) ) ]\n",
    "Counter(X_aa)\n",
    "\n",
    "plt.figure(figsize = (8,8))\n",
    "\n",
    "plt.subplot(221);\n",
    "plot_digits(X_aa[:25], images_per_row=5)\n",
    "\n",
    "plt.subplot(222);\n",
    "plot_digits(X_ab[:25], images_per_row=5)\n",
    "\n",
    "plt.subplot(223);\n",
    "plot_digits(X_ba[:25], images_per_row=5)\n",
    "\n",
    "plt.subplot(224);\n",
    "plot_digits(X_abb[:25], images_per_row=5)\n",
    "\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 左侧两个是被分类为3的图片\n",
    "# 右侧两个是被分类为5的图片\n",
    "# 大多数错误分类的图片看起来还是非常明显的错误\n",
    "# 原因： SGD是一个线性模型，它所作的就是为每个像素分配一个各类别的权重，当他看到新的图像，将加权后的像素强度汇总，从而得到一个分数进行分类\n",
    "# 数字3和5在一部分像素位上有区别，所有分类器很容易将其弄混\n",
    "# 通过上面图像，如果书写3的连接点左移。分类器可能将其分类为数字5，这个分类器对图像位移和旋转敏感\n",
    "# 减少混淆的方法之一就是对图像进行预处理，确保位于中心位置且没有旋转\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 多标签分类\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 1. 为每个实例产生多个类别，例如照片识别多个人脸\n",
    "# 分类器经过训练可以识别小红，小白，小军，一张照片里有小红，小白\n",
    "# 经过分类器，应该输出【1，1，0】，是小红。是小白，不是小军\n",
    "# 输出多个二元标签的分类系统统称为多标签分类系统\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "not all arguments converted during string formatting",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-85-be4c5586b963>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m \u001b[0my_train_large\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0my_train\u001b[0m \u001b[1;33m>=\u001b[0m \u001b[1;34m\"7\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[0my_train_odd\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0my_train\u001b[0m \u001b[1;33m%\u001b[0m \u001b[1;36m2\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      5\u001b[0m \u001b[0my_multilabel\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mc_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0my_train_large\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0my_train_odd\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      6\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mTypeError\u001b[0m: not all arguments converted during string formatting"
     ]
    }
   ],
   "source": [
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "\n",
    "y_train_large = (y_train >= \"7\")\n",
    "y_train_odd = (y_train % 2 == 1)\n",
    "y_multilabel = np.c_(y_train_large,y_train_odd)\n",
    "\n",
    "knn_clf = KNeighborsClassifier()\n",
    "knn_clf.fit(X_train , y_multilabel)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'knn_clf' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-86-33906decb44f>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# knn支持多标签分类，不是所有的分类都支持\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mknn_clf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpredict\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0msome_digit\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m: name 'knn_clf' is not defined"
     ]
    }
   ],
   "source": [
    "# knn支持多标签分类，不是所有的分类都支持\n",
    "\n",
    "knn_clf.predict([some_digit])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 评估多标签分类器方法很多，方法之一就是测量每个标签的F1分数，或者其他二元分类器指标，然后简单平均\n",
    "y_train_knn_pred = cross_val_predict(knn_clf,X_train,y_multilabel,cv=3)\n",
    "f1_score(y_multilabel,y_train_knn_prd,average=\"macro\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 上面假设了所有标签都同等重要，也可以给每个标签设置一个等于自生支持的权重（该目标标签实例的数量），设置average=“weighted\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 多输出分类\n",
    "## 例子，构建一个系统去除图片中的噪声，输入一张有噪声的图片，它将输入一张干净的数字图片，分类器输出是多个标签，一个像素一个标签，每个标签多个值（0--255）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 增加噪声，目标将图片还原为原始图片，床架训练集和测试集\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "noise = np.random.randint(0,100,(len(X_train),784))\n",
    "X_train_mod = X_train + noise\n",
    "noise = np.random.randint(0,100,(len(X_test),784))\n",
    "X_test_mod = X_test + noise\n",
    "y_train_mod = X_train\n",
    "y_test_mod = X_test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "some_index = 5500\n",
    "plt.subplot(121);\n",
    "plt.imshow(X_train_mod[some_index.reshape(28,28),cmap = matplotlib.cm.binary])\n",
    "plt.subplot(121);\n",
    "plt.imshow(X_train_mod[some_index.reshape(28,28),cmap = matplotlib.cm.binary])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "knn_clf.fit(X_train_mod,y_train_mod)\n",
    "clean_digit = knn_clf.predict([X_test_mod[some_index]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.imshow(clean_digit.reshape(28,28),cmap = matplotlib.cm.binary)\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
